blob: 39cec0d9cd1bf76275015216f6fdabf6e26b2ae7 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337 /* check for plausible wct, bcc and t2 data and parm sizes */
338 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000339 if (pSMB->hdr.WordCount >= 10) {
340 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
342 /* check that bcc is at least as big as parms + data */
343 /* check that bcc is less than negotiated smb buffer */
344 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000345 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000346 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000347 le16_to_cpu(pSMB->t2_rsp.DataCount);
Jeff Layton690c5222011-01-20 13:36:51 -0500348 if (total_size <= get_bcc(&pSMB->hdr) &&
349 total_size <
350 CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return 0;
352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 }
354 }
355 }
Steve French50c2f752007-07-13 00:33:32 +0000356 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 sizeof(struct smb_t2_rsp) + 16);
358 return rc;
359}
Jeff Layton690c5222011-01-20 13:36:51 -0500360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361int
362CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
363{
364 NEGOTIATE_REQ *pSMB;
365 NEGOTIATE_RSP *pSMBr;
366 int rc = 0;
367 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000368 int i;
Steve French50c2f752007-07-13 00:33:32 +0000369 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000371 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Steve French790fe572007-07-07 19:25:05 +0000373 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 server = ses->server;
375 else {
376 rc = -EIO;
377 return rc;
378 }
379 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
380 (void **) &pSMB, (void **) &pSMBr);
381 if (rc)
382 return rc;
Steve French750d1152006-06-27 06:28:30 +0000383
384 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000385 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000386 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000387 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400388 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000389
Joe Perchesb6b38f72010-04-21 03:50:45 +0000390 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000391
Steve French1982c342005-08-17 12:38:22 -0700392 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000393 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000394
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000395 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000396 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000397 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000398 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000399 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500400 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000401 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
402 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000403 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000404 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
405 }
Steve French50c2f752007-07-13 00:33:32 +0000406
Steve French39798772006-05-31 22:40:51 +0000407 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000408 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000409 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
410 count += strlen(protocols[i].name) + 1;
411 /* null at end of source and target buffers anyway */
412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 pSMB->hdr.smb_buf_length += count;
414 pSMB->ByteCount = cpu_to_le16(count);
415
416 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
417 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000418 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000419 goto neg_err_exit;
420
Jeff Layton9bf67e52010-04-24 07:57:46 -0400421 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
422 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000423 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400424 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000425 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000426 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000427 could not negotiate a common dialect */
428 rc = -EOPNOTSUPP;
429 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000430#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000431 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400432 && ((server->dialect == LANMAN_PROT)
433 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000434 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000435 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000436
Steve French790fe572007-07-07 19:25:05 +0000437 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000438 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000439 server->secType = LANMAN;
440 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000441 cERROR(1, "mount failed weak security disabled"
442 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000443 rc = -EOPNOTSUPP;
444 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000445 }
Steve French254e55e2006-06-04 05:53:15 +0000446 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
447 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
448 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000449 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000450 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000451 /* even though we do not use raw we might as well set this
452 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000453 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000454 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000455 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
456 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000457 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000458 server->capabilities = CAP_MPX_MODE;
459 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000460 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000461 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000462 /* OS/2 often does not set timezone therefore
463 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000464 * Could deviate slightly from the right zone.
465 * Smallest defined timezone difference is 15 minutes
466 * (i.e. Nepal). Rounding up/down is done to match
467 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000468 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000469 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000470 struct timespec ts, utc;
471 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400472 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
473 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000474 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000475 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000476 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000477 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000478 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000479 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000481 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000482 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000483 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000484 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000485 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000486 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000487 server->timeAdj = (int)tmp;
488 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000489 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000490 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000491
Steve French39798772006-05-31 22:40:51 +0000492
Steve French254e55e2006-06-04 05:53:15 +0000493 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000494 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000495
Steve French50c2f752007-07-13 00:33:32 +0000496 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000497 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500498 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000499 CIFS_CRYPTO_KEY_SIZE);
500 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
501 rc = -EIO; /* need cryptkey unless plain text */
502 goto neg_err_exit;
503 }
Steve French39798772006-05-31 22:40:51 +0000504
Steve Frenchf19159d2010-04-21 04:12:10 +0000505 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000506 /* we will not end up setting signing flags - as no signing
507 was in LANMAN and server did not return the flags on */
508 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000509#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000510 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000511 cERROR(1, "mount failed, cifs module not built "
512 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300513 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000514#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000515 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000516 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000517 /* unknown wct */
518 rc = -EOPNOTSUPP;
519 goto neg_err_exit;
520 }
521 /* else wct == 17 NTLM */
522 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000523 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000524 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000525
Steve French790fe572007-07-07 19:25:05 +0000526 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000527#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000528 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000529#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000530 cERROR(1, "Server requests plain text password"
531 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000532
Steve French790fe572007-07-07 19:25:05 +0000533 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000534 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000535 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000536 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000537 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000538 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000539 else if (secFlags & CIFSSEC_MAY_KRB5)
540 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000541 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000542 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000543 else if (secFlags & CIFSSEC_MAY_LANMAN)
544 server->secType = LANMAN;
545/* #ifdef CONFIG_CIFS_EXPERIMENTAL
546 else if (secFlags & CIFSSEC_MAY_PLNTXT)
547 server->secType = ??
548#endif */
549 else {
550 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000551 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000552 goto neg_err_exit;
553 }
554 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000555
Steve French254e55e2006-06-04 05:53:15 +0000556 /* one byte, so no need to convert this or EncryptionKeyLen from
557 little endian */
558 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
559 /* probably no need to store and check maxvcs */
560 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000562 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000563 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000564 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000565 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
566 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000567 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500568 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000569 CIFS_CRYPTO_KEY_SIZE);
570 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
571 && (pSMBr->EncryptionKeyLength == 0)) {
572 /* decode security blob */
573 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
574 rc = -EIO; /* no crypt key only if plain text pwd */
575 goto neg_err_exit;
576 }
577
578 /* BB might be helpful to save off the domain of server here */
579
Steve French50c2f752007-07-13 00:33:32 +0000580 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000581 (server->capabilities & CAP_EXTENDED_SECURITY)) {
582 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000583 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000585 goto neg_err_exit;
586 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530587 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500588 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530589 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000590 if (memcmp(server->server_GUID,
591 pSMBr->u.extended_response.
592 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000594 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000595 pSMBr->u.extended_response.GUID,
596 16);
597 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530599 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000600 memcpy(server->server_GUID,
601 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 }
Jeff Laytone187e442007-10-16 17:10:44 +0000603
604 if (count == 16) {
605 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000606 } else {
607 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400608 SecurityBlob, count - 16,
609 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000610 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000611 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000612 else
Steve French254e55e2006-06-04 05:53:15 +0000613 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500614 if (server->secType == Kerberos) {
615 if (!server->sec_kerberos &&
616 !server->sec_mskerberos)
617 rc = -EOPNOTSUPP;
618 } else if (server->secType == RawNTLMSSP) {
619 if (!server->sec_ntlmssp)
620 rc = -EOPNOTSUPP;
621 } else
622 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Steve French254e55e2006-06-04 05:53:15 +0000624 } else
625 server->capabilities &= ~CAP_EXTENDED_SECURITY;
626
Steve French6344a422006-06-12 04:18:35 +0000627#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000628signing_check:
Steve French6344a422006-06-12 04:18:35 +0000629#endif
Steve French762e5ab2007-06-28 18:41:42 +0000630 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
631 /* MUST_SIGN already includes the MAY_SIGN FLAG
632 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000633 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000634 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000635 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000636 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000637 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000638 rc = -EOPNOTSUPP;
639 }
Steve French50c2f752007-07-13 00:33:32 +0000640 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000641 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000642 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
643 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000644 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000645 if ((server->secMode &
646 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000647 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000648 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000649 } else
650 server->secMode |= SECMODE_SIGN_REQUIRED;
651 } else {
652 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000653 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000654 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000655 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 }
Steve French50c2f752007-07-13 00:33:32 +0000657
658neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700659 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000660
Joe Perchesb6b38f72010-04-21 03:50:45 +0000661 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 return rc;
663}
664
665int
666CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
667{
668 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Joe Perchesb6b38f72010-04-21 03:50:45 +0000671 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500672
673 /* BB: do we need to check this? These should never be NULL. */
674 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
675 return -EIO;
676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500678 * No need to return error on this operation if tid invalidated and
679 * closed on server already e.g. due to tcp session crashing. Also,
680 * the tcon is no longer on the list, so no need to take lock before
681 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 */
Steve French268875b2009-06-25 00:29:21 +0000683 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000684 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Steve French50c2f752007-07-13 00:33:32 +0000686 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700687 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500688 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return rc;
Steve French133672e2007-11-13 22:41:37 +0000690
691 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000693 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Steve French50c2f752007-07-13 00:33:32 +0000695 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500696 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 if (rc == -EAGAIN)
698 rc = 0;
699
700 return rc;
701}
702
Jeff Layton766fdbb2011-01-11 07:24:21 -0500703/*
704 * This is a no-op for now. We're not really interested in the reply, but
705 * rather in the fact that the server sent one and that server->lstrp
706 * gets updated.
707 *
708 * FIXME: maybe we should consider checking that the reply matches request?
709 */
710static void
711cifs_echo_callback(struct mid_q_entry *mid)
712{
713 struct TCP_Server_Info *server = mid->callback_data;
714
715 DeleteMidQEntry(mid);
716 atomic_dec(&server->inFlight);
717 wake_up(&server->request_q);
718}
719
720int
721CIFSSMBEcho(struct TCP_Server_Info *server)
722{
723 ECHO_REQ *smb;
724 int rc = 0;
725
726 cFYI(1, "In echo request");
727
728 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
729 if (rc)
730 return rc;
731
732 /* set up echo request */
733 smb->hdr.Tid = cpu_to_le16(0xffff);
734 smb->hdr.WordCount = cpu_to_le16(1);
735 smb->EchoCount = cpu_to_le16(1);
736 smb->ByteCount = cpu_to_le16(1);
737 smb->Data[0] = 'a';
738 smb->hdr.smb_buf_length += 3;
739
740 rc = cifs_call_async(server, (struct smb_hdr *)smb,
741 cifs_echo_callback, server);
742 if (rc)
743 cFYI(1, "Echo request failed: %d", rc);
744
745 cifs_small_buf_release(smb);
746
747 return rc;
748}
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750int
751CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
752{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 LOGOFF_ANDX_REQ *pSMB;
754 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Joe Perchesb6b38f72010-04-21 03:50:45 +0000756 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500757
758 /*
759 * BB: do we need to check validity of ses and server? They should
760 * always be valid since we have an active reference. If not, that
761 * should probably be a BUG()
762 */
763 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return -EIO;
765
Steve Frenchd7b619c2010-02-25 05:36:46 +0000766 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000767 if (ses->need_reconnect)
768 goto session_already_dead; /* no need to send SMBlogoff if uid
769 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
771 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000772 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return rc;
774 }
775
Steve French3b795212008-11-13 19:45:32 +0000776 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700777
Steve French3b795212008-11-13 19:45:32 +0000778 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
780 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 pSMB->hdr.Uid = ses->Suid;
783
784 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000785 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000786session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000787 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000790 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 error */
792 if (rc == -EAGAIN)
793 rc = 0;
794 return rc;
795}
796
797int
Steve French2d785a52007-07-15 01:48:57 +0000798CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
799 __u16 type, const struct nls_table *nls_codepage, int remap)
800{
801 TRANSACTION2_SPI_REQ *pSMB = NULL;
802 TRANSACTION2_SPI_RSP *pSMBr = NULL;
803 struct unlink_psx_rq *pRqD;
804 int name_len;
805 int rc = 0;
806 int bytes_returned = 0;
807 __u16 params, param_offset, offset, byte_count;
808
Joe Perchesb6b38f72010-04-21 03:50:45 +0000809 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000810PsxDelete:
811 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
812 (void **) &pSMBr);
813 if (rc)
814 return rc;
815
816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
817 name_len =
818 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
819 PATH_MAX, nls_codepage, remap);
820 name_len++; /* trailing null */
821 name_len *= 2;
822 } else { /* BB add path length overrun check */
823 name_len = strnlen(fileName, PATH_MAX);
824 name_len++; /* trailing null */
825 strncpy(pSMB->FileName, fileName, name_len);
826 }
827
828 params = 6 + name_len;
829 pSMB->MaxParameterCount = cpu_to_le16(2);
830 pSMB->MaxDataCount = 0; /* BB double check this with jra */
831 pSMB->MaxSetupCount = 0;
832 pSMB->Reserved = 0;
833 pSMB->Flags = 0;
834 pSMB->Timeout = 0;
835 pSMB->Reserved2 = 0;
836 param_offset = offsetof(struct smb_com_transaction2_spi_req,
837 InformationLevel) - 4;
838 offset = param_offset + params;
839
840 /* Setup pointer to Request Data (inode type) */
841 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
842 pRqD->type = cpu_to_le16(type);
843 pSMB->ParameterOffset = cpu_to_le16(param_offset);
844 pSMB->DataOffset = cpu_to_le16(offset);
845 pSMB->SetupCount = 1;
846 pSMB->Reserved3 = 0;
847 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
848 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
849
850 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
851 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
852 pSMB->ParameterCount = cpu_to_le16(params);
853 pSMB->TotalParameterCount = pSMB->ParameterCount;
854 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
855 pSMB->Reserved4 = 0;
856 pSMB->hdr.smb_buf_length += byte_count;
857 pSMB->ByteCount = cpu_to_le16(byte_count);
858 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000860 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000861 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000862 cifs_buf_release(pSMB);
863
864 cifs_stats_inc(&tcon->num_deletes);
865
866 if (rc == -EAGAIN)
867 goto PsxDelete;
868
869 return rc;
870}
871
872int
Steve French737b7582005-04-28 22:41:06 -0700873CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
874 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 DELETE_FILE_REQ *pSMB = NULL;
877 DELETE_FILE_RSP *pSMBr = NULL;
878 int rc = 0;
879 int bytes_returned;
880 int name_len;
881
882DelFileRetry:
883 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
884 (void **) &pSMBr);
885 if (rc)
886 return rc;
887
888 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
889 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000890 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700891 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 name_len++; /* trailing null */
893 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700894 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 name_len = strnlen(fileName, PATH_MAX);
896 name_len++; /* trailing null */
897 strncpy(pSMB->fileName, fileName, name_len);
898 }
899 pSMB->SearchAttributes =
900 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
901 pSMB->BufferFormat = 0x04;
902 pSMB->hdr.smb_buf_length += name_len + 1;
903 pSMB->ByteCount = cpu_to_le16(name_len + 1);
904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700906 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000907 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000908 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 cifs_buf_release(pSMB);
911 if (rc == -EAGAIN)
912 goto DelFileRetry;
913
914 return rc;
915}
916
917int
Steve French50c2f752007-07-13 00:33:32 +0000918CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700919 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920{
921 DELETE_DIRECTORY_REQ *pSMB = NULL;
922 DELETE_DIRECTORY_RSP *pSMBr = NULL;
923 int rc = 0;
924 int bytes_returned;
925 int name_len;
926
Joe Perchesb6b38f72010-04-21 03:50:45 +0000927 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928RmDirRetry:
929 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
930 (void **) &pSMBr);
931 if (rc)
932 return rc;
933
934 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700935 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
936 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 name_len++; /* trailing null */
938 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700939 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 name_len = strnlen(dirName, PATH_MAX);
941 name_len++; /* trailing null */
942 strncpy(pSMB->DirName, dirName, name_len);
943 }
944
945 pSMB->BufferFormat = 0x04;
946 pSMB->hdr.smb_buf_length += name_len + 1;
947 pSMB->ByteCount = cpu_to_le16(name_len + 1);
948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700950 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000951 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000952 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 cifs_buf_release(pSMB);
955 if (rc == -EAGAIN)
956 goto RmDirRetry;
957 return rc;
958}
959
960int
961CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700962 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
964 int rc = 0;
965 CREATE_DIRECTORY_REQ *pSMB = NULL;
966 CREATE_DIRECTORY_RSP *pSMBr = NULL;
967 int bytes_returned;
968 int name_len;
969
Joe Perchesb6b38f72010-04-21 03:50:45 +0000970 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971MkDirRetry:
972 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
973 (void **) &pSMBr);
974 if (rc)
975 return rc;
976
977 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000978 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700979 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 name_len++; /* trailing null */
981 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700982 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 name_len = strnlen(name, PATH_MAX);
984 name_len++; /* trailing null */
985 strncpy(pSMB->DirName, name, name_len);
986 }
987
988 pSMB->BufferFormat = 0x04;
989 pSMB->hdr.smb_buf_length += name_len + 1;
990 pSMB->ByteCount = cpu_to_le16(name_len + 1);
991 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
992 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700993 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000994 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000995 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 cifs_buf_release(pSMB);
998 if (rc == -EAGAIN)
999 goto MkDirRetry;
1000 return rc;
1001}
1002
Steve French2dd29d32007-04-23 22:07:35 +00001003int
1004CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001005 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001006 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001007 const struct nls_table *nls_codepage, int remap)
1008{
1009 TRANSACTION2_SPI_REQ *pSMB = NULL;
1010 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1011 int name_len;
1012 int rc = 0;
1013 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001014 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001015 OPEN_PSX_REQ *pdata;
1016 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001017
Joe Perchesb6b38f72010-04-21 03:50:45 +00001018 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001019PsxCreat:
1020 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1021 (void **) &pSMBr);
1022 if (rc)
1023 return rc;
1024
1025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1026 name_len =
1027 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1028 PATH_MAX, nls_codepage, remap);
1029 name_len++; /* trailing null */
1030 name_len *= 2;
1031 } else { /* BB improve the check for buffer overruns BB */
1032 name_len = strnlen(name, PATH_MAX);
1033 name_len++; /* trailing null */
1034 strncpy(pSMB->FileName, name, name_len);
1035 }
1036
1037 params = 6 + name_len;
1038 count = sizeof(OPEN_PSX_REQ);
1039 pSMB->MaxParameterCount = cpu_to_le16(2);
1040 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1041 pSMB->MaxSetupCount = 0;
1042 pSMB->Reserved = 0;
1043 pSMB->Flags = 0;
1044 pSMB->Timeout = 0;
1045 pSMB->Reserved2 = 0;
1046 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001047 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001048 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001049 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001050 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001051 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001052 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001053 pdata->OpenFlags = cpu_to_le32(*pOplock);
1054 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1055 pSMB->DataOffset = cpu_to_le16(offset);
1056 pSMB->SetupCount = 1;
1057 pSMB->Reserved3 = 0;
1058 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1059 byte_count = 3 /* pad */ + params + count;
1060
1061 pSMB->DataCount = cpu_to_le16(count);
1062 pSMB->ParameterCount = cpu_to_le16(params);
1063 pSMB->TotalDataCount = pSMB->DataCount;
1064 pSMB->TotalParameterCount = pSMB->ParameterCount;
1065 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1066 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001067 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001068 pSMB->ByteCount = cpu_to_le16(byte_count);
1069 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1070 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1071 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001072 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001073 goto psx_create_err;
1074 }
1075
Joe Perchesb6b38f72010-04-21 03:50:45 +00001076 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1078
1079 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1080 rc = -EIO; /* bad smb */
1081 goto psx_create_err;
1082 }
1083
1084 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001085 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001086 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001087
Steve French2dd29d32007-04-23 22:07:35 +00001088 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001089 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001090 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1091 /* Let caller know file was created so we can set the mode. */
1092 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001093 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001094 *pOplock |= CIFS_CREATE_ACTION;
1095 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001096 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1097 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001098 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001099 } else {
Steve French790fe572007-07-07 19:25:05 +00001100 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001101 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001102 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001103 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001104 goto psx_create_err;
1105 }
Steve French50c2f752007-07-13 00:33:32 +00001106 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001107 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001108 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001109 }
Steve French2dd29d32007-04-23 22:07:35 +00001110
1111psx_create_err:
1112 cifs_buf_release(pSMB);
1113
Steve French65bc98b2009-07-10 15:27:25 +00001114 if (posix_flags & SMB_O_DIRECTORY)
1115 cifs_stats_inc(&tcon->num_posixmkdirs);
1116 else
1117 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001118
1119 if (rc == -EAGAIN)
1120 goto PsxCreat;
1121
Steve French50c2f752007-07-13 00:33:32 +00001122 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001123}
1124
Steve Frencha9d02ad2005-08-24 23:06:05 -07001125static __u16 convert_disposition(int disposition)
1126{
1127 __u16 ofun = 0;
1128
1129 switch (disposition) {
1130 case FILE_SUPERSEDE:
1131 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1132 break;
1133 case FILE_OPEN:
1134 ofun = SMBOPEN_OAPPEND;
1135 break;
1136 case FILE_CREATE:
1137 ofun = SMBOPEN_OCREATE;
1138 break;
1139 case FILE_OPEN_IF:
1140 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1141 break;
1142 case FILE_OVERWRITE:
1143 ofun = SMBOPEN_OTRUNC;
1144 break;
1145 case FILE_OVERWRITE_IF:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1147 break;
1148 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001149 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001150 ofun = SMBOPEN_OAPPEND; /* regular open */
1151 }
1152 return ofun;
1153}
1154
Jeff Layton35fc37d2008-05-14 10:22:03 -07001155static int
1156access_flags_to_smbopen_mode(const int access_flags)
1157{
1158 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1159
1160 if (masked_flags == GENERIC_READ)
1161 return SMBOPEN_READ;
1162 else if (masked_flags == GENERIC_WRITE)
1163 return SMBOPEN_WRITE;
1164
1165 /* just go for read/write */
1166 return SMBOPEN_READWRITE;
1167}
1168
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169int
1170SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1171 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001172 const int access_flags, const int create_options, __u16 *netfid,
1173 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 const struct nls_table *nls_codepage, int remap)
1175{
1176 int rc = -EACCES;
1177 OPENX_REQ *pSMB = NULL;
1178 OPENX_RSP *pSMBr = NULL;
1179 int bytes_returned;
1180 int name_len;
1181 __u16 count;
1182
1183OldOpenRetry:
1184 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1185 (void **) &pSMBr);
1186 if (rc)
1187 return rc;
1188
1189 pSMB->AndXCommand = 0xFF; /* none */
1190
1191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1192 count = 1; /* account for one byte pad to word boundary */
1193 name_len =
1194 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1195 fileName, PATH_MAX, nls_codepage, remap);
1196 name_len++; /* trailing null */
1197 name_len *= 2;
1198 } else { /* BB improve check for buffer overruns BB */
1199 count = 0; /* no pad */
1200 name_len = strnlen(fileName, PATH_MAX);
1201 name_len++; /* trailing null */
1202 strncpy(pSMB->fileName, fileName, name_len);
1203 }
1204 if (*pOplock & REQ_OPLOCK)
1205 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001206 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001208
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001210 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1212 /* set file as system file if special file such
1213 as fifo and server expecting SFU style and
1214 no Unix extensions */
1215
Steve French790fe572007-07-07 19:25:05 +00001216 if (create_options & CREATE_OPTION_SPECIAL)
1217 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001218 else /* BB FIXME BB */
1219 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220
Jeff Layton67750fb2008-05-09 22:28:02 +00001221 if (create_options & CREATE_OPTION_READONLY)
1222 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223
1224 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001225/* pSMB->CreateOptions = cpu_to_le32(create_options &
1226 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001228
1229 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001230 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 count += name_len;
1232 pSMB->hdr.smb_buf_length += count;
1233
1234 pSMB->ByteCount = cpu_to_le16(count);
1235 /* long_op set to 1 to allow for oplock break timeouts */
1236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001237 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238 cifs_stats_inc(&tcon->num_opens);
1239 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001240 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 } else {
1242 /* BB verify if wct == 15 */
1243
Steve French582d21e2008-05-13 04:54:12 +00001244/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245
1246 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1247 /* Let caller know file was created so we can set the mode. */
1248 /* Do we care about the CreateAction in any other cases? */
1249 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001250/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 *pOplock |= CIFS_CREATE_ACTION; */
1252 /* BB FIXME END */
1253
Steve French790fe572007-07-07 19:25:05 +00001254 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1256 pfile_info->LastAccessTime = 0; /* BB fixme */
1257 pfile_info->LastWriteTime = 0; /* BB fixme */
1258 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001259 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001260 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001262 pfile_info->AllocationSize =
1263 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1264 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001266 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 }
1268 }
1269
1270 cifs_buf_release(pSMB);
1271 if (rc == -EAGAIN)
1272 goto OldOpenRetry;
1273 return rc;
1274}
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276int
1277CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1278 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001279 const int access_flags, const int create_options, __u16 *netfid,
1280 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001281 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
1283 int rc = -EACCES;
1284 OPEN_REQ *pSMB = NULL;
1285 OPEN_RSP *pSMBr = NULL;
1286 int bytes_returned;
1287 int name_len;
1288 __u16 count;
1289
1290openRetry:
1291 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1292 (void **) &pSMBr);
1293 if (rc)
1294 return rc;
1295
1296 pSMB->AndXCommand = 0xFF; /* none */
1297
1298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1299 count = 1; /* account for one byte pad to word boundary */
1300 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001301 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001302 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 name_len++; /* trailing null */
1304 name_len *= 2;
1305 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001306 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 count = 0; /* no pad */
1308 name_len = strnlen(fileName, PATH_MAX);
1309 name_len++; /* trailing null */
1310 pSMB->NameLength = cpu_to_le16(name_len);
1311 strncpy(pSMB->fileName, fileName, name_len);
1312 }
1313 if (*pOplock & REQ_OPLOCK)
1314 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001315 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1318 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001319 /* set file as system file if special file such
1320 as fifo and server expecting SFU style and
1321 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001322 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001323 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1324 else
1325 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 /* XP does not handle ATTR_POSIX_SEMANTICS */
1328 /* but it helps speed up case sensitive checks for other
1329 servers such as Samba */
1330 if (tcon->ses->capabilities & CAP_UNIX)
1331 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1332
Jeff Layton67750fb2008-05-09 22:28:02 +00001333 if (create_options & CREATE_OPTION_READONLY)
1334 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1337 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001338 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001339 /* BB Expirement with various impersonation levels and verify */
1340 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 pSMB->SecurityFlags =
1342 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1343
1344 count += name_len;
1345 pSMB->hdr.smb_buf_length += count;
1346
1347 pSMB->ByteCount = cpu_to_le16(count);
1348 /* long_op set to 1 to allow for oplock break timeouts */
1349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001350 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001351 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001353 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 } else {
Steve French09d1db52005-04-28 22:41:08 -07001355 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1357 /* Let caller know file was created so we can set the mode. */
1358 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001359 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001360 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001361 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001362 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1363 36 /* CreationTime to Attributes */);
1364 /* the file_info buf is endian converted by caller */
1365 pfile_info->AllocationSize = pSMBr->AllocationSize;
1366 pfile_info->EndOfFile = pSMBr->EndOfFile;
1367 pfile_info->NumberOfLinks = cpu_to_le32(1);
1368 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 cifs_buf_release(pSMB);
1373 if (rc == -EAGAIN)
1374 goto openRetry;
1375 return rc;
1376}
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378int
Steve French50c2f752007-07-13 00:33:32 +00001379CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1380 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1381 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382{
1383 int rc = -EACCES;
1384 READ_REQ *pSMB = NULL;
1385 READ_RSP *pSMBr = NULL;
1386 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001387 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001388 int resp_buf_type = 0;
1389 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Joe Perchesb6b38f72010-04-21 03:50:45 +00001391 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001392 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001393 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001394 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001395 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001396 if ((lseek >> 32) > 0) {
1397 /* can not handle this big offset for old */
1398 return -EIO;
1399 }
1400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001403 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 if (rc)
1405 return rc;
1406
1407 /* tcon and ses pointer are checked in smb_init */
1408 if (tcon->ses->server == NULL)
1409 return -ECONNABORTED;
1410
Steve Frenchec637e32005-12-12 20:53:18 -08001411 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 pSMB->Fid = netfid;
1413 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001414 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001415 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 pSMB->Remaining = 0;
1418 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1419 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001420 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1422 else {
1423 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001424 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001425 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001426 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001427 }
Steve Frenchec637e32005-12-12 20:53:18 -08001428
1429 iov[0].iov_base = (char *)pSMB;
1430 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001431 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001432 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001433 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001434 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001436 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 } else {
1438 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1439 data_length = data_length << 16;
1440 data_length += le16_to_cpu(pSMBr->DataLength);
1441 *nbytes = data_length;
1442
1443 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001444 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001446 cFYI(1, "bad length %d for count %d",
1447 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 rc = -EIO;
1449 *nbytes = 0;
1450 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001451 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001452 le16_to_cpu(pSMBr->DataOffset);
1453/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001454 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001455 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001456 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001457 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001458 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 }
1460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Steve French4b8f9302006-02-26 16:41:18 +00001462/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001463 if (*buf) {
1464 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001465 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001466 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001467 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001468 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001469 /* return buffer to caller to free */
1470 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001471 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001472 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001473 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001474 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001475 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001476
1477 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 since file handle passed in no longer valid */
1479 return rc;
1480}
1481
Steve Frenchec637e32005-12-12 20:53:18 -08001482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483int
1484CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1485 const int netfid, const unsigned int count,
1486 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001487 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488{
1489 int rc = -EACCES;
1490 WRITE_REQ *pSMB = NULL;
1491 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001492 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 __u32 bytes_sent;
1494 __u16 byte_count;
1495
Steve Frencha24e2d72010-04-03 17:20:21 +00001496 *nbytes = 0;
1497
Joe Perchesb6b38f72010-04-21 03:50:45 +00001498 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001499 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001500 return -ECONNABORTED;
1501
Steve French790fe572007-07-07 19:25:05 +00001502 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001503 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001504 else {
Steve French1c955182005-08-30 20:58:07 -07001505 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001506 if ((offset >> 32) > 0) {
1507 /* can not handle big offset for old srv */
1508 return -EIO;
1509 }
1510 }
Steve French1c955182005-08-30 20:58:07 -07001511
1512 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 (void **) &pSMBr);
1514 if (rc)
1515 return rc;
1516 /* tcon and ses pointer are checked in smb_init */
1517 if (tcon->ses->server == NULL)
1518 return -ECONNABORTED;
1519
1520 pSMB->AndXCommand = 0xFF; /* none */
1521 pSMB->Fid = netfid;
1522 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001523 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001524 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 pSMB->Reserved = 0xFFFFFFFF;
1527 pSMB->WriteMode = 0;
1528 pSMB->Remaining = 0;
1529
Steve French50c2f752007-07-13 00:33:32 +00001530 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 can send more if LARGE_WRITE_X capability returned by the server and if
1532 our buffer is big enough or if we convert to iovecs on socket writes
1533 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001534 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1536 } else {
1537 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1538 & ~0xFF;
1539 }
1540
1541 if (bytes_sent > count)
1542 bytes_sent = count;
1543 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001544 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001545 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001546 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001547 else if (ubuf) {
1548 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 cifs_buf_release(pSMB);
1550 return -EFAULT;
1551 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001552 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 /* No buffer */
1554 cifs_buf_release(pSMB);
1555 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001557 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001558 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001559 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1563 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001565
Steve French790fe572007-07-07 19:25:05 +00001566 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001567 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001568 else { /* old style write has byte count 4 bytes earlier
1569 so 4 bytes pad */
1570 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001571 (struct smb_com_writex_req *)pSMB;
1572 pSMBW->ByteCount = cpu_to_le16(byte_count);
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1576 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001577 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001579 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 } else {
1581 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1582 *nbytes = (*nbytes) << 16;
1583 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301584
1585 /*
1586 * Mask off high 16 bits when bytes written as returned by the
1587 * server is greater than bytes requested by the client. Some
1588 * OS/2 servers are known to set incorrect CountHigh values.
1589 */
1590 if (*nbytes > count)
1591 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 }
1593
1594 cifs_buf_release(pSMB);
1595
Steve French50c2f752007-07-13 00:33:32 +00001596 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 since file handle passed in no longer valid */
1598
1599 return rc;
1600}
1601
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001602int
1603CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001605 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1606 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607{
1608 int rc = -EACCES;
1609 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001610 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001611 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001612 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001614 *nbytes = 0;
1615
Joe Perchesb6b38f72010-04-21 03:50:45 +00001616 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001617
Steve French4c3130e2008-12-09 00:28:16 +00001618 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001619 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001620 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001621 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001622 if ((offset >> 32) > 0) {
1623 /* can not handle big offset for old srv */
1624 return -EIO;
1625 }
1626 }
Steve French8cc64c62005-10-03 13:49:43 -07001627 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 if (rc)
1629 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 /* tcon and ses pointer are checked in smb_init */
1631 if (tcon->ses->server == NULL)
1632 return -ECONNABORTED;
1633
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001634 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 pSMB->Fid = netfid;
1636 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001637 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001638 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 pSMB->Reserved = 0xFFFFFFFF;
1640 pSMB->WriteMode = 0;
1641 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001644 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Steve French3e844692005-10-03 13:37:24 -07001646 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1647 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001648 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001649 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001650 pSMB->hdr.smb_buf_length += count+1;
1651 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001652 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1653 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001654 pSMB->ByteCount = cpu_to_le16(count + 1);
1655 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001656 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001657 (struct smb_com_writex_req *)pSMB;
1658 pSMBW->ByteCount = cpu_to_le16(count + 5);
1659 }
Steve French3e844692005-10-03 13:37:24 -07001660 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001661 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001662 iov[0].iov_len = smb_hdr_len + 4;
1663 else /* wct == 12 pad bigger by four bytes */
1664 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001665
Steve French3e844692005-10-03 13:37:24 -07001666
Steve Frenchec637e32005-12-12 20:53:18 -08001667 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001668 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001669 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001671 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001672 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001673 /* presumably this can not happen, but best to be safe */
1674 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001675 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001676 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001677 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1678 *nbytes = (*nbytes) << 16;
1679 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301680
1681 /*
1682 * Mask off high 16 bits when bytes written as returned by the
1683 * server is greater than bytes requested by the client. OS/2
1684 * servers are known to set incorrect CountHigh values.
1685 */
1686 if (*nbytes > count)
1687 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Steve French4b8f9302006-02-26 16:41:18 +00001690/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001691 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001692 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001693 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001694 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Steve French50c2f752007-07-13 00:33:32 +00001696 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 since file handle passed in no longer valid */
1698
1699 return rc;
1700}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001701
1702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703int
1704CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1705 const __u16 smb_file_id, const __u64 len,
1706 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001707 const __u32 numLock, const __u8 lockType,
1708 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709{
1710 int rc = 0;
1711 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001712/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 int bytes_returned;
1714 int timeout = 0;
1715 __u16 count;
1716
Joe Perchesb6b38f72010-04-21 03:50:45 +00001717 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001718 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1719
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 if (rc)
1721 return rc;
1722
Steve French790fe572007-07-07 19:25:05 +00001723 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001724 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001726 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001727 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1729 } else {
1730 pSMB->Timeout = 0;
1731 }
1732
1733 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1734 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1735 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001736 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 pSMB->AndXCommand = 0xFF; /* none */
1738 pSMB->Fid = smb_file_id; /* netfid stays le */
1739
Steve French790fe572007-07-07 19:25:05 +00001740 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1742 /* BB where to store pid high? */
1743 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1744 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1745 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1746 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1747 count = sizeof(LOCKING_ANDX_RANGE);
1748 } else {
1749 /* oplock break */
1750 count = 0;
1751 }
1752 pSMB->hdr.smb_buf_length += count;
1753 pSMB->ByteCount = cpu_to_le16(count);
1754
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001755 if (waitFlag) {
1756 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001757 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001758 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001759 } else {
Steve French133672e2007-11-13 22:41:37 +00001760 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1761 timeout);
1762 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001763 }
Steve Frencha4544342005-08-24 13:59:35 -07001764 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001765 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001766 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
Steve French50c2f752007-07-13 00:33:32 +00001768 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 since file handle passed in no longer valid */
1770 return rc;
1771}
1772
1773int
Steve French08547b02006-02-28 22:39:25 +00001774CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1775 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001776 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001777 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001778{
1779 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1780 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001781 struct cifs_posix_lock *parm_data;
1782 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001783 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001784 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001785 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001786 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001787 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001788
Joe Perchesb6b38f72010-04-21 03:50:45 +00001789 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001790
Steve French790fe572007-07-07 19:25:05 +00001791 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001792 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001793
Steve French08547b02006-02-28 22:39:25 +00001794 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1795
1796 if (rc)
1797 return rc;
1798
1799 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1800
Steve French50c2f752007-07-13 00:33:32 +00001801 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001802 pSMB->MaxSetupCount = 0;
1803 pSMB->Reserved = 0;
1804 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001805 pSMB->Reserved2 = 0;
1806 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1807 offset = param_offset + params;
1808
Steve French08547b02006-02-28 22:39:25 +00001809 count = sizeof(struct cifs_posix_lock);
1810 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001811 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001812 pSMB->SetupCount = 1;
1813 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001814 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001815 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1816 else
1817 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1818 byte_count = 3 /* pad */ + params + count;
1819 pSMB->DataCount = cpu_to_le16(count);
1820 pSMB->ParameterCount = cpu_to_le16(params);
1821 pSMB->TotalDataCount = pSMB->DataCount;
1822 pSMB->TotalParameterCount = pSMB->ParameterCount;
1823 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001824 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001825 (((char *) &pSMB->hdr.Protocol) + offset);
1826
1827 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001828 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001829 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001830 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001831 pSMB->Timeout = cpu_to_le32(-1);
1832 } else
1833 pSMB->Timeout = 0;
1834
Steve French08547b02006-02-28 22:39:25 +00001835 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001836 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001837 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001838
1839 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001840 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001841 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1842 pSMB->Reserved4 = 0;
1843 pSMB->hdr.smb_buf_length += byte_count;
1844 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001845 if (waitFlag) {
1846 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1847 (struct smb_hdr *) pSMBr, &bytes_returned);
1848 } else {
Steve French133672e2007-11-13 22:41:37 +00001849 iov[0].iov_base = (char *)pSMB;
1850 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1851 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1852 &resp_buf_type, timeout);
1853 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1854 not try to free it twice below on exit */
1855 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001856 }
1857
Steve French08547b02006-02-28 22:39:25 +00001858 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001859 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001860 } else if (get_flag) {
1861 /* lock structure can be returned on get */
1862 __u16 data_offset;
1863 __u16 data_count;
1864 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001865
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001866 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1867 rc = -EIO; /* bad smb */
1868 goto plk_err_exit;
1869 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001870 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1871 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001872 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001873 rc = -EIO;
1874 goto plk_err_exit;
1875 }
1876 parm_data = (struct cifs_posix_lock *)
1877 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001878 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001879 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001880 else {
1881 if (parm_data->lock_type ==
1882 __constant_cpu_to_le16(CIFS_RDLCK))
1883 pLockData->fl_type = F_RDLCK;
1884 else if (parm_data->lock_type ==
1885 __constant_cpu_to_le16(CIFS_WRLCK))
1886 pLockData->fl_type = F_WRLCK;
1887
1888 pLockData->fl_start = parm_data->start;
1889 pLockData->fl_end = parm_data->start +
1890 parm_data->length - 1;
1891 pLockData->fl_pid = parm_data->pid;
1892 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001893 }
Steve French50c2f752007-07-13 00:33:32 +00001894
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001895plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001896 if (pSMB)
1897 cifs_small_buf_release(pSMB);
1898
Steve French133672e2007-11-13 22:41:37 +00001899 if (resp_buf_type == CIFS_SMALL_BUFFER)
1900 cifs_small_buf_release(iov[0].iov_base);
1901 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1902 cifs_buf_release(iov[0].iov_base);
1903
Steve French08547b02006-02-28 22:39:25 +00001904 /* Note: On -EAGAIN error only caller can retry on handle based calls
1905 since file handle passed in no longer valid */
1906
1907 return rc;
1908}
1909
1910
1911int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1913{
1914 int rc = 0;
1915 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001916 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918/* do not retry on dead session on close */
1919 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001920 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 return 0;
1922 if (rc)
1923 return rc;
1924
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001926 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001928 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001929 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001931 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001933 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 }
1935 }
1936
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001938 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 rc = 0;
1940
1941 return rc;
1942}
1943
1944int
Steve Frenchb298f222009-02-21 21:17:43 +00001945CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1946{
1947 int rc = 0;
1948 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001949 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001950
1951 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1952 if (rc)
1953 return rc;
1954
1955 pSMB->FileID = (__u16) smb_file_id;
1956 pSMB->ByteCount = 0;
1957 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1958 cifs_stats_inc(&tcon->num_flushes);
1959 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001960 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001961
1962 return rc;
1963}
1964
1965int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1967 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001968 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969{
1970 int rc = 0;
1971 RENAME_REQ *pSMB = NULL;
1972 RENAME_RSP *pSMBr = NULL;
1973 int bytes_returned;
1974 int name_len, name_len2;
1975 __u16 count;
1976
Joe Perchesb6b38f72010-04-21 03:50:45 +00001977 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978renameRetry:
1979 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1980 (void **) &pSMBr);
1981 if (rc)
1982 return rc;
1983
1984 pSMB->BufferFormat = 0x04;
1985 pSMB->SearchAttributes =
1986 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1987 ATTR_DIRECTORY);
1988
1989 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1990 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001991 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001992 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 name_len++; /* trailing null */
1994 name_len *= 2;
1995 pSMB->OldFileName[name_len] = 0x04; /* pad */
1996 /* protocol requires ASCII signature byte on Unicode string */
1997 pSMB->OldFileName[name_len + 1] = 0x00;
1998 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001999 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002000 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2002 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002003 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 name_len = strnlen(fromName, PATH_MAX);
2005 name_len++; /* trailing null */
2006 strncpy(pSMB->OldFileName, fromName, name_len);
2007 name_len2 = strnlen(toName, PATH_MAX);
2008 name_len2++; /* trailing null */
2009 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2010 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2011 name_len2++; /* trailing null */
2012 name_len2++; /* signature byte */
2013 }
2014
2015 count = 1 /* 1st signature byte */ + name_len + name_len2;
2016 pSMB->hdr.smb_buf_length += count;
2017 pSMB->ByteCount = cpu_to_le16(count);
2018
2019 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2020 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002021 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002022 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002023 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 cifs_buf_release(pSMB);
2026
2027 if (rc == -EAGAIN)
2028 goto renameRetry;
2029
2030 return rc;
2031}
2032
Steve French50c2f752007-07-13 00:33:32 +00002033int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002034 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002035 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036{
2037 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2038 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002039 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 char *data_offset;
2041 char dummy_string[30];
2042 int rc = 0;
2043 int bytes_returned = 0;
2044 int len_of_str;
2045 __u16 params, param_offset, offset, count, byte_count;
2046
Joe Perchesb6b38f72010-04-21 03:50:45 +00002047 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2049 (void **) &pSMBr);
2050 if (rc)
2051 return rc;
2052
2053 params = 6;
2054 pSMB->MaxSetupCount = 0;
2055 pSMB->Reserved = 0;
2056 pSMB->Flags = 0;
2057 pSMB->Timeout = 0;
2058 pSMB->Reserved2 = 0;
2059 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2060 offset = param_offset + params;
2061
2062 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2063 rename_info = (struct set_file_rename *) data_offset;
2064 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002065 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 pSMB->SetupCount = 1;
2067 pSMB->Reserved3 = 0;
2068 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2069 byte_count = 3 /* pad */ + params;
2070 pSMB->ParameterCount = cpu_to_le16(params);
2071 pSMB->TotalParameterCount = pSMB->ParameterCount;
2072 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2073 pSMB->DataOffset = cpu_to_le16(offset);
2074 /* construct random name ".cifs_tmp<inodenum><mid>" */
2075 rename_info->overwrite = cpu_to_le32(1);
2076 rename_info->root_fid = 0;
2077 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002078 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002079 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2080 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002081 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002083 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002084 target_name, PATH_MAX, nls_codepage,
2085 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 }
2087 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002088 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 byte_count += count;
2090 pSMB->DataCount = cpu_to_le16(count);
2091 pSMB->TotalDataCount = pSMB->DataCount;
2092 pSMB->Fid = netfid;
2093 pSMB->InformationLevel =
2094 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2095 pSMB->Reserved4 = 0;
2096 pSMB->hdr.smb_buf_length += byte_count;
2097 pSMB->ByteCount = cpu_to_le16(byte_count);
2098 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002100 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002101 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002102 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 cifs_buf_release(pSMB);
2105
2106 /* Note: On -EAGAIN error only caller can retry on handle based calls
2107 since file handle passed in no longer valid */
2108
2109 return rc;
2110}
2111
2112int
Steve French50c2f752007-07-13 00:33:32 +00002113CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2114 const __u16 target_tid, const char *toName, const int flags,
2115 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116{
2117 int rc = 0;
2118 COPY_REQ *pSMB = NULL;
2119 COPY_RSP *pSMBr = NULL;
2120 int bytes_returned;
2121 int name_len, name_len2;
2122 __u16 count;
2123
Joe Perchesb6b38f72010-04-21 03:50:45 +00002124 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125copyRetry:
2126 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2127 (void **) &pSMBr);
2128 if (rc)
2129 return rc;
2130
2131 pSMB->BufferFormat = 0x04;
2132 pSMB->Tid2 = target_tid;
2133
2134 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2135
2136 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002137 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002138 fromName, PATH_MAX, nls_codepage,
2139 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 name_len++; /* trailing null */
2141 name_len *= 2;
2142 pSMB->OldFileName[name_len] = 0x04; /* pad */
2143 /* protocol requires ASCII signature byte on Unicode string */
2144 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002145 name_len2 =
2146 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002147 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2149 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002150 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 name_len = strnlen(fromName, PATH_MAX);
2152 name_len++; /* trailing null */
2153 strncpy(pSMB->OldFileName, fromName, name_len);
2154 name_len2 = strnlen(toName, PATH_MAX);
2155 name_len2++; /* trailing null */
2156 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2157 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2158 name_len2++; /* trailing null */
2159 name_len2++; /* signature byte */
2160 }
2161
2162 count = 1 /* 1st signature byte */ + name_len + name_len2;
2163 pSMB->hdr.smb_buf_length += count;
2164 pSMB->ByteCount = cpu_to_le16(count);
2165
2166 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2167 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2168 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002169 cFYI(1, "Send error in copy = %d with %d files copied",
2170 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 }
Steve French0d817bc2008-05-22 02:02:03 +00002172 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173
2174 if (rc == -EAGAIN)
2175 goto copyRetry;
2176
2177 return rc;
2178}
2179
2180int
2181CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2182 const char *fromName, const char *toName,
2183 const struct nls_table *nls_codepage)
2184{
2185 TRANSACTION2_SPI_REQ *pSMB = NULL;
2186 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2187 char *data_offset;
2188 int name_len;
2189 int name_len_target;
2190 int rc = 0;
2191 int bytes_returned = 0;
2192 __u16 params, param_offset, offset, byte_count;
2193
Joe Perchesb6b38f72010-04-21 03:50:45 +00002194 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195createSymLinkRetry:
2196 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2197 (void **) &pSMBr);
2198 if (rc)
2199 return rc;
2200
2201 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2202 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002203 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 /* find define for this maxpathcomponent */
2205 , nls_codepage);
2206 name_len++; /* trailing null */
2207 name_len *= 2;
2208
Steve French50c2f752007-07-13 00:33:32 +00002209 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 name_len = strnlen(fromName, PATH_MAX);
2211 name_len++; /* trailing null */
2212 strncpy(pSMB->FileName, fromName, name_len);
2213 }
2214 params = 6 + name_len;
2215 pSMB->MaxSetupCount = 0;
2216 pSMB->Reserved = 0;
2217 pSMB->Flags = 0;
2218 pSMB->Timeout = 0;
2219 pSMB->Reserved2 = 0;
2220 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002221 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 offset = param_offset + params;
2223
2224 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2225 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2226 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002227 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 /* find define for this maxpathcomponent */
2229 , nls_codepage);
2230 name_len_target++; /* trailing null */
2231 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002232 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 name_len_target = strnlen(toName, PATH_MAX);
2234 name_len_target++; /* trailing null */
2235 strncpy(data_offset, toName, name_len_target);
2236 }
2237
2238 pSMB->MaxParameterCount = cpu_to_le16(2);
2239 /* BB find exact max on data count below from sess */
2240 pSMB->MaxDataCount = cpu_to_le16(1000);
2241 pSMB->SetupCount = 1;
2242 pSMB->Reserved3 = 0;
2243 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2244 byte_count = 3 /* pad */ + params + name_len_target;
2245 pSMB->DataCount = cpu_to_le16(name_len_target);
2246 pSMB->ParameterCount = cpu_to_le16(params);
2247 pSMB->TotalDataCount = pSMB->DataCount;
2248 pSMB->TotalParameterCount = pSMB->ParameterCount;
2249 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2250 pSMB->DataOffset = cpu_to_le16(offset);
2251 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2252 pSMB->Reserved4 = 0;
2253 pSMB->hdr.smb_buf_length += byte_count;
2254 pSMB->ByteCount = cpu_to_le16(byte_count);
2255 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2256 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002257 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002258 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002259 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
Steve French0d817bc2008-05-22 02:02:03 +00002261 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262
2263 if (rc == -EAGAIN)
2264 goto createSymLinkRetry;
2265
2266 return rc;
2267}
2268
2269int
2270CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2271 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002272 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273{
2274 TRANSACTION2_SPI_REQ *pSMB = NULL;
2275 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2276 char *data_offset;
2277 int name_len;
2278 int name_len_target;
2279 int rc = 0;
2280 int bytes_returned = 0;
2281 __u16 params, param_offset, offset, byte_count;
2282
Joe Perchesb6b38f72010-04-21 03:50:45 +00002283 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284createHardLinkRetry:
2285 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2286 (void **) &pSMBr);
2287 if (rc)
2288 return rc;
2289
2290 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002291 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002292 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 name_len++; /* trailing null */
2294 name_len *= 2;
2295
Steve French50c2f752007-07-13 00:33:32 +00002296 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 name_len = strnlen(toName, PATH_MAX);
2298 name_len++; /* trailing null */
2299 strncpy(pSMB->FileName, toName, name_len);
2300 }
2301 params = 6 + name_len;
2302 pSMB->MaxSetupCount = 0;
2303 pSMB->Reserved = 0;
2304 pSMB->Flags = 0;
2305 pSMB->Timeout = 0;
2306 pSMB->Reserved2 = 0;
2307 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002308 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 offset = param_offset + params;
2310
2311 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2313 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002314 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002315 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 name_len_target++; /* trailing null */
2317 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002318 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 name_len_target = strnlen(fromName, PATH_MAX);
2320 name_len_target++; /* trailing null */
2321 strncpy(data_offset, fromName, name_len_target);
2322 }
2323
2324 pSMB->MaxParameterCount = cpu_to_le16(2);
2325 /* BB find exact max on data count below from sess*/
2326 pSMB->MaxDataCount = cpu_to_le16(1000);
2327 pSMB->SetupCount = 1;
2328 pSMB->Reserved3 = 0;
2329 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2330 byte_count = 3 /* pad */ + params + name_len_target;
2331 pSMB->ParameterCount = cpu_to_le16(params);
2332 pSMB->TotalParameterCount = pSMB->ParameterCount;
2333 pSMB->DataCount = cpu_to_le16(name_len_target);
2334 pSMB->TotalDataCount = pSMB->DataCount;
2335 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2336 pSMB->DataOffset = cpu_to_le16(offset);
2337 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2338 pSMB->Reserved4 = 0;
2339 pSMB->hdr.smb_buf_length += byte_count;
2340 pSMB->ByteCount = cpu_to_le16(byte_count);
2341 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2342 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002343 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002344 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002345 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347 cifs_buf_release(pSMB);
2348 if (rc == -EAGAIN)
2349 goto createHardLinkRetry;
2350
2351 return rc;
2352}
2353
2354int
2355CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2356 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002357 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358{
2359 int rc = 0;
2360 NT_RENAME_REQ *pSMB = NULL;
2361 RENAME_RSP *pSMBr = NULL;
2362 int bytes_returned;
2363 int name_len, name_len2;
2364 __u16 count;
2365
Joe Perchesb6b38f72010-04-21 03:50:45 +00002366 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367winCreateHardLinkRetry:
2368
2369 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2370 (void **) &pSMBr);
2371 if (rc)
2372 return rc;
2373
2374 pSMB->SearchAttributes =
2375 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2376 ATTR_DIRECTORY);
2377 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2378 pSMB->ClusterCount = 0;
2379
2380 pSMB->BufferFormat = 0x04;
2381
2382 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2383 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002384 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002385 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 name_len++; /* trailing null */
2387 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002388
2389 /* protocol specifies ASCII buffer format (0x04) for unicode */
2390 pSMB->OldFileName[name_len] = 0x04;
2391 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002393 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002394 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2396 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002397 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 name_len = strnlen(fromName, PATH_MAX);
2399 name_len++; /* trailing null */
2400 strncpy(pSMB->OldFileName, fromName, name_len);
2401 name_len2 = strnlen(toName, PATH_MAX);
2402 name_len2++; /* trailing null */
2403 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2404 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2405 name_len2++; /* trailing null */
2406 name_len2++; /* signature byte */
2407 }
2408
2409 count = 1 /* string type byte */ + name_len + name_len2;
2410 pSMB->hdr.smb_buf_length += count;
2411 pSMB->ByteCount = cpu_to_le16(count);
2412
2413 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2414 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002415 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002416 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002417 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002418
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 cifs_buf_release(pSMB);
2420 if (rc == -EAGAIN)
2421 goto winCreateHardLinkRetry;
2422
2423 return rc;
2424}
2425
2426int
2427CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002428 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 const struct nls_table *nls_codepage)
2430{
2431/* SMB_QUERY_FILE_UNIX_LINK */
2432 TRANSACTION2_QPI_REQ *pSMB = NULL;
2433 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2434 int rc = 0;
2435 int bytes_returned;
2436 int name_len;
2437 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002438 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Joe Perchesb6b38f72010-04-21 03:50:45 +00002440 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442querySymLinkRetry:
2443 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2444 (void **) &pSMBr);
2445 if (rc)
2446 return rc;
2447
2448 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2449 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002450 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2451 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 name_len++; /* trailing null */
2453 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002454 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 name_len = strnlen(searchName, PATH_MAX);
2456 name_len++; /* trailing null */
2457 strncpy(pSMB->FileName, searchName, name_len);
2458 }
2459
2460 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2461 pSMB->TotalDataCount = 0;
2462 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002463 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 pSMB->MaxSetupCount = 0;
2465 pSMB->Reserved = 0;
2466 pSMB->Flags = 0;
2467 pSMB->Timeout = 0;
2468 pSMB->Reserved2 = 0;
2469 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002470 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 pSMB->DataCount = 0;
2472 pSMB->DataOffset = 0;
2473 pSMB->SetupCount = 1;
2474 pSMB->Reserved3 = 0;
2475 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2476 byte_count = params + 1 /* pad */ ;
2477 pSMB->TotalParameterCount = cpu_to_le16(params);
2478 pSMB->ParameterCount = pSMB->TotalParameterCount;
2479 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2480 pSMB->Reserved4 = 0;
2481 pSMB->hdr.smb_buf_length += byte_count;
2482 pSMB->ByteCount = cpu_to_le16(byte_count);
2483
2484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2486 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002487 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 } else {
2489 /* decode response */
2490
2491 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002493 if (rc || (pSMBr->ByteCount < 2))
2494 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002496 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002497 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
Jeff Layton460b9692009-04-30 07:17:56 -04002499 data_start = ((char *) &pSMBr->hdr.Protocol) +
2500 le16_to_cpu(pSMBr->t2.DataOffset);
2501
Steve French0e0d2cf2009-05-01 05:27:32 +00002502 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2503 is_unicode = true;
2504 else
2505 is_unicode = false;
2506
Steve French737b7582005-04-28 22:41:06 -07002507 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002508 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002509 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002510 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002511 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 }
2513 }
2514 cifs_buf_release(pSMB);
2515 if (rc == -EAGAIN)
2516 goto querySymLinkRetry;
2517 return rc;
2518}
2519
Parag Warudkarc9489772007-10-23 18:09:48 +00002520#ifdef CONFIG_CIFS_EXPERIMENTAL
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521int
2522CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2523 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002524 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 const struct nls_table *nls_codepage)
2526{
2527 int rc = 0;
2528 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002529 struct smb_com_transaction_ioctl_req *pSMB;
2530 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Joe Perchesb6b38f72010-04-21 03:50:45 +00002532 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2534 (void **) &pSMBr);
2535 if (rc)
2536 return rc;
2537
2538 pSMB->TotalParameterCount = 0 ;
2539 pSMB->TotalDataCount = 0;
2540 pSMB->MaxParameterCount = cpu_to_le32(2);
2541 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002542 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2543 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 pSMB->MaxSetupCount = 4;
2545 pSMB->Reserved = 0;
2546 pSMB->ParameterOffset = 0;
2547 pSMB->DataCount = 0;
2548 pSMB->DataOffset = 0;
2549 pSMB->SetupCount = 4;
2550 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2551 pSMB->ParameterCount = pSMB->TotalParameterCount;
2552 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2553 pSMB->IsFsctl = 1; /* FSCTL */
2554 pSMB->IsRootFlag = 0;
2555 pSMB->Fid = fid; /* file handle always le */
2556 pSMB->ByteCount = 0;
2557
2558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2559 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2560 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002561 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 } else { /* decode response */
2563 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2564 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002565 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 /* BB also check enough total bytes returned */
2567 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002568 goto qreparse_out;
2569 }
2570 if (data_count && (data_count < 2048)) {
2571 char *end_of_smb = 2 /* sizeof byte count */ +
2572 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573
Steve Frenchafe48c32009-05-02 05:25:46 +00002574 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002575 (struct reparse_data *)
2576 ((char *)&pSMBr->hdr.Protocol
2577 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002578 if ((char *)reparse_buf >= end_of_smb) {
2579 rc = -EIO;
2580 goto qreparse_out;
2581 }
2582 if ((reparse_buf->LinkNamesBuf +
2583 reparse_buf->TargetNameOffset +
2584 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002585 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002586 rc = -EIO;
2587 goto qreparse_out;
2588 }
Steve French50c2f752007-07-13 00:33:32 +00002589
Steve Frenchafe48c32009-05-02 05:25:46 +00002590 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2591 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002592 (reparse_buf->LinkNamesBuf +
2593 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002594 buflen,
2595 reparse_buf->TargetNameLen,
2596 nls_codepage, 0);
2597 } else { /* ASCII names */
2598 strncpy(symlinkinfo,
2599 reparse_buf->LinkNamesBuf +
2600 reparse_buf->TargetNameOffset,
2601 min_t(const int, buflen,
2602 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002604 } else {
2605 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002606 cFYI(1, "Invalid return data count on "
2607 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002609 symlinkinfo[buflen] = 0; /* just in case so the caller
2610 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002611 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 }
Steve French989c7e52009-05-02 05:32:20 +00002613
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002615 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
2617 /* Note: On -EAGAIN error only caller can retry on handle based calls
2618 since file handle passed in no longer valid */
2619
2620 return rc;
2621}
Steve Frenchafe48c32009-05-02 05:25:46 +00002622#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623
2624#ifdef CONFIG_CIFS_POSIX
2625
2626/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002627static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2628 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629{
2630 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002631 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2632 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2633 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002634 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636 return;
2637}
2638
2639/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002640static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2641 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642{
2643 int size = 0;
2644 int i;
2645 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002646 struct cifs_posix_ace *pACE;
2647 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2648 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2651 return -EOPNOTSUPP;
2652
Steve French790fe572007-07-07 19:25:05 +00002653 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 count = le16_to_cpu(cifs_acl->access_entry_count);
2655 pACE = &cifs_acl->ace_array[0];
2656 size = sizeof(struct cifs_posix_acl);
2657 size += sizeof(struct cifs_posix_ace) * count;
2658 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002659 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002660 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2661 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 return -EINVAL;
2663 }
Steve French790fe572007-07-07 19:25:05 +00002664 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 count = le16_to_cpu(cifs_acl->access_entry_count);
2666 size = sizeof(struct cifs_posix_acl);
2667 size += sizeof(struct cifs_posix_ace) * count;
2668/* skip past access ACEs to get to default ACEs */
2669 pACE = &cifs_acl->ace_array[count];
2670 count = le16_to_cpu(cifs_acl->default_entry_count);
2671 size += sizeof(struct cifs_posix_ace) * count;
2672 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002673 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 return -EINVAL;
2675 } else {
2676 /* illegal type */
2677 return -EINVAL;
2678 }
2679
2680 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002681 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002682 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002683 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 return -ERANGE;
2685 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002686 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002687 for (i = 0; i < count ; i++) {
2688 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2689 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 }
2691 }
2692 return size;
2693}
2694
Steve French50c2f752007-07-13 00:33:32 +00002695static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2696 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
2698 __u16 rc = 0; /* 0 = ACL converted ok */
2699
Steve Frenchff7feac2005-11-15 16:45:16 -08002700 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2701 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002703 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 /* Probably no need to le convert -1 on any arch but can not hurt */
2705 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002706 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002707 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002708 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 return rc;
2710}
2711
2712/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002713static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2714 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715{
2716 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002717 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2718 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 int count;
2720 int i;
2721
Steve French790fe572007-07-07 19:25:05 +00002722 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 return 0;
2724
2725 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002726 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002727 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002728 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002729 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002730 cFYI(1, "unknown POSIX ACL version %d",
2731 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 return 0;
2733 }
2734 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002735 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002736 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002737 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002738 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002740 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 return 0;
2742 }
Steve French50c2f752007-07-13 00:33:32 +00002743 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2745 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002746 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 /* ACE not converted */
2748 break;
2749 }
2750 }
Steve French790fe572007-07-07 19:25:05 +00002751 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2753 rc += sizeof(struct cifs_posix_acl);
2754 /* BB add check to make sure ACL does not overflow SMB */
2755 }
2756 return rc;
2757}
2758
2759int
2760CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002761 const unsigned char *searchName,
2762 char *acl_inf, const int buflen, const int acl_type,
2763 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764{
2765/* SMB_QUERY_POSIX_ACL */
2766 TRANSACTION2_QPI_REQ *pSMB = NULL;
2767 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2768 int rc = 0;
2769 int bytes_returned;
2770 int name_len;
2771 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002772
Joe Perchesb6b38f72010-04-21 03:50:45 +00002773 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775queryAclRetry:
2776 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2777 (void **) &pSMBr);
2778 if (rc)
2779 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002780
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2782 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002783 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002784 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 name_len++; /* trailing null */
2786 name_len *= 2;
2787 pSMB->FileName[name_len] = 0;
2788 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002789 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 name_len = strnlen(searchName, PATH_MAX);
2791 name_len++; /* trailing null */
2792 strncpy(pSMB->FileName, searchName, name_len);
2793 }
2794
2795 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2796 pSMB->TotalDataCount = 0;
2797 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002798 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 pSMB->MaxDataCount = cpu_to_le16(4000);
2800 pSMB->MaxSetupCount = 0;
2801 pSMB->Reserved = 0;
2802 pSMB->Flags = 0;
2803 pSMB->Timeout = 0;
2804 pSMB->Reserved2 = 0;
2805 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002806 offsetof(struct smb_com_transaction2_qpi_req,
2807 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 pSMB->DataCount = 0;
2809 pSMB->DataOffset = 0;
2810 pSMB->SetupCount = 1;
2811 pSMB->Reserved3 = 0;
2812 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2813 byte_count = params + 1 /* pad */ ;
2814 pSMB->TotalParameterCount = cpu_to_le16(params);
2815 pSMB->ParameterCount = pSMB->TotalParameterCount;
2816 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2817 pSMB->Reserved4 = 0;
2818 pSMB->hdr.smb_buf_length += byte_count;
2819 pSMB->ByteCount = cpu_to_le16(byte_count);
2820
2821 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2822 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002823 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002825 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 } else {
2827 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002828
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2830 if (rc || (pSMBr->ByteCount < 2))
2831 /* BB also check enough total bytes returned */
2832 rc = -EIO; /* bad smb */
2833 else {
2834 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2835 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2836 rc = cifs_copy_posix_acl(acl_inf,
2837 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002838 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 }
2840 }
2841 cifs_buf_release(pSMB);
2842 if (rc == -EAGAIN)
2843 goto queryAclRetry;
2844 return rc;
2845}
2846
2847int
2848CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002849 const unsigned char *fileName,
2850 const char *local_acl, const int buflen,
2851 const int acl_type,
2852 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853{
2854 struct smb_com_transaction2_spi_req *pSMB = NULL;
2855 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2856 char *parm_data;
2857 int name_len;
2858 int rc = 0;
2859 int bytes_returned = 0;
2860 __u16 params, byte_count, data_count, param_offset, offset;
2861
Joe Perchesb6b38f72010-04-21 03:50:45 +00002862 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863setAclRetry:
2864 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002865 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 if (rc)
2867 return rc;
2868 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2869 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002870 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002871 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 name_len++; /* trailing null */
2873 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002874 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len = strnlen(fileName, PATH_MAX);
2876 name_len++; /* trailing null */
2877 strncpy(pSMB->FileName, fileName, name_len);
2878 }
2879 params = 6 + name_len;
2880 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002881 /* BB find max SMB size from sess */
2882 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 pSMB->MaxSetupCount = 0;
2884 pSMB->Reserved = 0;
2885 pSMB->Flags = 0;
2886 pSMB->Timeout = 0;
2887 pSMB->Reserved2 = 0;
2888 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002889 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 offset = param_offset + params;
2891 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2892 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2893
2894 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002895 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
Steve French790fe572007-07-07 19:25:05 +00002897 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 rc = -EOPNOTSUPP;
2899 goto setACLerrorExit;
2900 }
2901 pSMB->DataOffset = cpu_to_le16(offset);
2902 pSMB->SetupCount = 1;
2903 pSMB->Reserved3 = 0;
2904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2905 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2906 byte_count = 3 /* pad */ + params + data_count;
2907 pSMB->DataCount = cpu_to_le16(data_count);
2908 pSMB->TotalDataCount = pSMB->DataCount;
2909 pSMB->ParameterCount = cpu_to_le16(params);
2910 pSMB->TotalParameterCount = pSMB->ParameterCount;
2911 pSMB->Reserved4 = 0;
2912 pSMB->hdr.smb_buf_length += byte_count;
2913 pSMB->ByteCount = cpu_to_le16(byte_count);
2914 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002915 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002916 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002917 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918
2919setACLerrorExit:
2920 cifs_buf_release(pSMB);
2921 if (rc == -EAGAIN)
2922 goto setAclRetry;
2923 return rc;
2924}
2925
Steve Frenchf654bac2005-04-28 22:41:04 -07002926/* BB fix tabs in this function FIXME BB */
2927int
2928CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002929 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002930{
Steve French50c2f752007-07-13 00:33:32 +00002931 int rc = 0;
2932 struct smb_t2_qfi_req *pSMB = NULL;
2933 struct smb_t2_qfi_rsp *pSMBr = NULL;
2934 int bytes_returned;
2935 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002936
Joe Perchesb6b38f72010-04-21 03:50:45 +00002937 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002938 if (tcon == NULL)
2939 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002940
2941GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002942 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2943 (void **) &pSMBr);
2944 if (rc)
2945 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002946
Steve Frenchad7a2922008-02-07 23:25:02 +00002947 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002948 pSMB->t2.TotalDataCount = 0;
2949 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2950 /* BB find exact max data count below from sess structure BB */
2951 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2952 pSMB->t2.MaxSetupCount = 0;
2953 pSMB->t2.Reserved = 0;
2954 pSMB->t2.Flags = 0;
2955 pSMB->t2.Timeout = 0;
2956 pSMB->t2.Reserved2 = 0;
2957 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2958 Fid) - 4);
2959 pSMB->t2.DataCount = 0;
2960 pSMB->t2.DataOffset = 0;
2961 pSMB->t2.SetupCount = 1;
2962 pSMB->t2.Reserved3 = 0;
2963 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2964 byte_count = params + 1 /* pad */ ;
2965 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2966 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2967 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2968 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002969 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002970 pSMB->hdr.smb_buf_length += byte_count;
2971 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002972
Steve French790fe572007-07-07 19:25:05 +00002973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2975 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002976 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00002977 } else {
2978 /* decode response */
2979 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2980 if (rc || (pSMBr->ByteCount < 2))
2981 /* BB also check enough total bytes returned */
2982 /* If rc should we check for EOPNOSUPP and
2983 disable the srvino flag? or in caller? */
2984 rc = -EIO; /* bad smb */
2985 else {
2986 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2987 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2988 struct file_chattr_info *pfinfo;
2989 /* BB Do we need a cast or hash here ? */
2990 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002991 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002992 rc = -EIO;
2993 goto GetExtAttrOut;
2994 }
2995 pfinfo = (struct file_chattr_info *)
2996 (data_offset + (char *) &pSMBr->hdr.Protocol);
2997 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07002998 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00002999 }
3000 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003001GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003002 cifs_buf_release(pSMB);
3003 if (rc == -EAGAIN)
3004 goto GetExtAttrRetry;
3005 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003006}
3007
Steve Frenchf654bac2005-04-28 22:41:04 -07003008#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
Jeff Layton79df1ba2010-12-06 12:52:08 -05003010#ifdef CONFIG_CIFS_ACL
3011/*
3012 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3013 * all NT TRANSACTS that we init here have total parm and data under about 400
3014 * bytes (to fit in small cifs buffer size), which is the case so far, it
3015 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3016 * returned setup area) and MaxParameterCount (returned parms size) must be set
3017 * by caller
3018 */
3019static int
3020smb_init_nttransact(const __u16 sub_command, const int setup_count,
3021 const int parm_len, struct cifsTconInfo *tcon,
3022 void **ret_buf)
3023{
3024 int rc;
3025 __u32 temp_offset;
3026 struct smb_com_ntransact_req *pSMB;
3027
3028 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3029 (void **)&pSMB);
3030 if (rc)
3031 return rc;
3032 *ret_buf = (void *)pSMB;
3033 pSMB->Reserved = 0;
3034 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3035 pSMB->TotalDataCount = 0;
3036 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3037 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3038 pSMB->ParameterCount = pSMB->TotalParameterCount;
3039 pSMB->DataCount = pSMB->TotalDataCount;
3040 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3041 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3042 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3043 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3044 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3045 pSMB->SubCommand = cpu_to_le16(sub_command);
3046 return 0;
3047}
3048
3049static int
3050validate_ntransact(char *buf, char **ppparm, char **ppdata,
3051 __u32 *pparmlen, __u32 *pdatalen)
3052{
3053 char *end_of_smb;
3054 __u32 data_count, data_offset, parm_count, parm_offset;
3055 struct smb_com_ntransact_rsp *pSMBr;
3056
3057 *pdatalen = 0;
3058 *pparmlen = 0;
3059
3060 if (buf == NULL)
3061 return -EINVAL;
3062
3063 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3064
3065 /* ByteCount was converted from little endian in SendReceive */
3066 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
3067 (char *)&pSMBr->ByteCount;
3068
3069 data_offset = le32_to_cpu(pSMBr->DataOffset);
3070 data_count = le32_to_cpu(pSMBr->DataCount);
3071 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3072 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3073
3074 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3075 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3076
3077 /* should we also check that parm and data areas do not overlap? */
3078 if (*ppparm > end_of_smb) {
3079 cFYI(1, "parms start after end of smb");
3080 return -EINVAL;
3081 } else if (parm_count + *ppparm > end_of_smb) {
3082 cFYI(1, "parm end after end of smb");
3083 return -EINVAL;
3084 } else if (*ppdata > end_of_smb) {
3085 cFYI(1, "data starts after end of smb");
3086 return -EINVAL;
3087 } else if (data_count + *ppdata > end_of_smb) {
3088 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3089 *ppdata, data_count, (data_count + *ppdata),
3090 end_of_smb, pSMBr);
3091 return -EINVAL;
3092 } else if (parm_count + data_count > pSMBr->ByteCount) {
3093 cFYI(1, "parm count and data count larger than SMB");
3094 return -EINVAL;
3095 }
3096 *pdatalen = data_count;
3097 *pparmlen = parm_count;
3098 return 0;
3099}
3100
Steve French0a4b92c2006-01-12 15:44:21 -08003101/* Get Security Descriptor (by handle) from remote server for a file or dir */
3102int
3103CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003104 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003105{
3106 int rc = 0;
3107 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003108 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003109 struct kvec iov[1];
3110
Joe Perchesb6b38f72010-04-21 03:50:45 +00003111 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003112
Steve French630f3f0c2007-10-25 21:17:17 +00003113 *pbuflen = 0;
3114 *acl_inf = NULL;
3115
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003116 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003117 8 /* parm len */, tcon, (void **) &pSMB);
3118 if (rc)
3119 return rc;
3120
3121 pSMB->MaxParameterCount = cpu_to_le32(4);
3122 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3123 pSMB->MaxSetupCount = 0;
3124 pSMB->Fid = fid; /* file handle always le */
3125 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3126 CIFS_ACL_DACL);
3127 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3128 pSMB->hdr.smb_buf_length += 11;
3129 iov[0].iov_base = (char *)pSMB;
3130 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3131
Steve Frencha761ac52007-10-18 21:45:27 +00003132 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003133 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003134 cifs_stats_inc(&tcon->num_acl_get);
3135 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003136 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003137 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003138 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003139 __u32 parm_len;
3140 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003141 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003142 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003143
3144/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003145 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003146 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003147 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003148 goto qsec_out;
3149 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3150
Joe Perchesb6b38f72010-04-21 03:50:45 +00003151 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003152
3153 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3154 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003155 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003156 goto qsec_out;
3157 }
3158
3159/* BB check that data area is minimum length and as big as acl_len */
3160
Steve Frenchaf6f4612007-10-16 18:40:37 +00003161 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003162 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003163 cERROR(1, "acl length %d does not match %d",
3164 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003165 if (*pbuflen > acl_len)
3166 *pbuflen = acl_len;
3167 }
Steve French0a4b92c2006-01-12 15:44:21 -08003168
Steve French630f3f0c2007-10-25 21:17:17 +00003169 /* check if buffer is big enough for the acl
3170 header followed by the smallest SID */
3171 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3172 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003173 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003174 rc = -EINVAL;
3175 *pbuflen = 0;
3176 } else {
3177 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3178 if (*acl_inf == NULL) {
3179 *pbuflen = 0;
3180 rc = -ENOMEM;
3181 }
3182 memcpy(*acl_inf, pdata, *pbuflen);
3183 }
Steve French0a4b92c2006-01-12 15:44:21 -08003184 }
3185qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003186 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003187 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003188 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003189 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003190/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003191 return rc;
3192}
Steve French97837582007-12-31 07:47:21 +00003193
3194int
3195CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3196 struct cifs_ntsd *pntsd, __u32 acllen)
3197{
3198 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3199 int rc = 0;
3200 int bytes_returned = 0;
3201 SET_SEC_DESC_REQ *pSMB = NULL;
3202 NTRANSACT_RSP *pSMBr = NULL;
3203
3204setCifsAclRetry:
3205 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3206 (void **) &pSMBr);
3207 if (rc)
3208 return (rc);
3209
3210 pSMB->MaxSetupCount = 0;
3211 pSMB->Reserved = 0;
3212
3213 param_count = 8;
3214 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3215 data_count = acllen;
3216 data_offset = param_offset + param_count;
3217 byte_count = 3 /* pad */ + param_count;
3218
3219 pSMB->DataCount = cpu_to_le32(data_count);
3220 pSMB->TotalDataCount = pSMB->DataCount;
3221 pSMB->MaxParameterCount = cpu_to_le32(4);
3222 pSMB->MaxDataCount = cpu_to_le32(16384);
3223 pSMB->ParameterCount = cpu_to_le32(param_count);
3224 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3225 pSMB->TotalParameterCount = pSMB->ParameterCount;
3226 pSMB->DataOffset = cpu_to_le32(data_offset);
3227 pSMB->SetupCount = 0;
3228 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3229 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3230
3231 pSMB->Fid = fid; /* file handle always le */
3232 pSMB->Reserved2 = 0;
3233 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3234
3235 if (pntsd && acllen) {
3236 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3237 (char *) pntsd,
3238 acllen);
3239 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3240
3241 } else
3242 pSMB->hdr.smb_buf_length += byte_count;
3243
3244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246
Joe Perchesb6b38f72010-04-21 03:50:45 +00003247 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003248 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003249 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003250 cifs_buf_release(pSMB);
3251
3252 if (rc == -EAGAIN)
3253 goto setCifsAclRetry;
3254
3255 return (rc);
3256}
3257
Jeff Layton79df1ba2010-12-06 12:52:08 -05003258#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003259
Steve French6b8edfe2005-08-23 20:26:03 -07003260/* Legacy Query Path Information call for lookup to old servers such
3261 as Win9x/WinME */
3262int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003263 const unsigned char *searchName,
3264 FILE_ALL_INFO *pFinfo,
3265 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003266{
Steve Frenchad7a2922008-02-07 23:25:02 +00003267 QUERY_INFORMATION_REQ *pSMB;
3268 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003269 int rc = 0;
3270 int bytes_returned;
3271 int name_len;
3272
Joe Perchesb6b38f72010-04-21 03:50:45 +00003273 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003274QInfRetry:
3275 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003276 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003277 if (rc)
3278 return rc;
3279
3280 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3281 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003282 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3283 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003284 name_len++; /* trailing null */
3285 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003286 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003287 name_len = strnlen(searchName, PATH_MAX);
3288 name_len++; /* trailing null */
3289 strncpy(pSMB->FileName, searchName, name_len);
3290 }
3291 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003292 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003293 pSMB->hdr.smb_buf_length += (__u16) name_len;
3294 pSMB->ByteCount = cpu_to_le16(name_len);
3295
3296 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003297 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003298 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003299 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003300 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003301 struct timespec ts;
3302 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003303
3304 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003305 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003306 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003307 ts.tv_nsec = 0;
3308 ts.tv_sec = time;
3309 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003310 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003311 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3312 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003313 pFinfo->AllocationSize =
3314 cpu_to_le64(le32_to_cpu(pSMBr->size));
3315 pFinfo->EndOfFile = pFinfo->AllocationSize;
3316 pFinfo->Attributes =
3317 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003318 } else
3319 rc = -EIO; /* bad buffer passed in */
3320
3321 cifs_buf_release(pSMB);
3322
3323 if (rc == -EAGAIN)
3324 goto QInfRetry;
3325
3326 return rc;
3327}
3328
Jeff Laytonbcd53572010-02-12 07:44:16 -05003329int
3330CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3331 u16 netfid, FILE_ALL_INFO *pFindData)
3332{
3333 struct smb_t2_qfi_req *pSMB = NULL;
3334 struct smb_t2_qfi_rsp *pSMBr = NULL;
3335 int rc = 0;
3336 int bytes_returned;
3337 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003338
Jeff Laytonbcd53572010-02-12 07:44:16 -05003339QFileInfoRetry:
3340 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3341 (void **) &pSMBr);
3342 if (rc)
3343 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003344
Jeff Laytonbcd53572010-02-12 07:44:16 -05003345 params = 2 /* level */ + 2 /* fid */;
3346 pSMB->t2.TotalDataCount = 0;
3347 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3348 /* BB find exact max data count below from sess structure BB */
3349 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3350 pSMB->t2.MaxSetupCount = 0;
3351 pSMB->t2.Reserved = 0;
3352 pSMB->t2.Flags = 0;
3353 pSMB->t2.Timeout = 0;
3354 pSMB->t2.Reserved2 = 0;
3355 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3356 Fid) - 4);
3357 pSMB->t2.DataCount = 0;
3358 pSMB->t2.DataOffset = 0;
3359 pSMB->t2.SetupCount = 1;
3360 pSMB->t2.Reserved3 = 0;
3361 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3362 byte_count = params + 1 /* pad */ ;
3363 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3364 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3365 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3366 pSMB->Pad = 0;
3367 pSMB->Fid = netfid;
3368 pSMB->hdr.smb_buf_length += byte_count;
3369
3370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3372 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003373 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003374 } else { /* decode response */
3375 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3376
3377 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3378 rc = -EIO;
3379 else if (pSMBr->ByteCount < 40)
3380 rc = -EIO; /* bad smb */
3381 else if (pFindData) {
3382 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3383 memcpy((char *) pFindData,
3384 (char *) &pSMBr->hdr.Protocol +
3385 data_offset, sizeof(FILE_ALL_INFO));
3386 } else
3387 rc = -ENOMEM;
3388 }
3389 cifs_buf_release(pSMB);
3390 if (rc == -EAGAIN)
3391 goto QFileInfoRetry;
3392
3393 return rc;
3394}
Steve French6b8edfe2005-08-23 20:26:03 -07003395
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396int
3397CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3398 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003399 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003400 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003401 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402{
3403/* level 263 SMB_QUERY_FILE_ALL_INFO */
3404 TRANSACTION2_QPI_REQ *pSMB = NULL;
3405 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3406 int rc = 0;
3407 int bytes_returned;
3408 int name_len;
3409 __u16 params, byte_count;
3410
Joe Perchesb6b38f72010-04-21 03:50:45 +00003411/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412QPathInfoRetry:
3413 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3414 (void **) &pSMBr);
3415 if (rc)
3416 return rc;
3417
3418 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3419 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003420 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003421 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 name_len++; /* trailing null */
3423 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003424 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 name_len = strnlen(searchName, PATH_MAX);
3426 name_len++; /* trailing null */
3427 strncpy(pSMB->FileName, searchName, name_len);
3428 }
3429
Steve French50c2f752007-07-13 00:33:32 +00003430 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 pSMB->TotalDataCount = 0;
3432 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003433 /* BB find exact max SMB PDU from sess structure BB */
3434 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 pSMB->MaxSetupCount = 0;
3436 pSMB->Reserved = 0;
3437 pSMB->Flags = 0;
3438 pSMB->Timeout = 0;
3439 pSMB->Reserved2 = 0;
3440 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003441 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 pSMB->DataCount = 0;
3443 pSMB->DataOffset = 0;
3444 pSMB->SetupCount = 1;
3445 pSMB->Reserved3 = 0;
3446 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3447 byte_count = params + 1 /* pad */ ;
3448 pSMB->TotalParameterCount = cpu_to_le16(params);
3449 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003450 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003451 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3452 else
3453 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 pSMB->Reserved4 = 0;
3455 pSMB->hdr.smb_buf_length += byte_count;
3456 pSMB->ByteCount = cpu_to_le16(byte_count);
3457
3458 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3460 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003461 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 } else { /* decode response */
3463 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3464
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003465 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3466 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003467 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003469 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003470 rc = -EIO; /* 24 or 26 expected but we do not read
3471 last field */
3472 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003473 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003475
3476 /* On legacy responses we do not read the last field,
3477 EAsize, fortunately since it varies by subdialect and
3478 also note it differs on Set vs. Get, ie two bytes or 4
3479 bytes depending but we don't care here */
3480 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003481 size = sizeof(FILE_INFO_STANDARD);
3482 else
3483 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 memcpy((char *) pFindData,
3485 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003486 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 } else
3488 rc = -ENOMEM;
3489 }
3490 cifs_buf_release(pSMB);
3491 if (rc == -EAGAIN)
3492 goto QPathInfoRetry;
3493
3494 return rc;
3495}
3496
3497int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003498CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3499 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3500{
3501 struct smb_t2_qfi_req *pSMB = NULL;
3502 struct smb_t2_qfi_rsp *pSMBr = NULL;
3503 int rc = 0;
3504 int bytes_returned;
3505 __u16 params, byte_count;
3506
3507UnixQFileInfoRetry:
3508 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3509 (void **) &pSMBr);
3510 if (rc)
3511 return rc;
3512
3513 params = 2 /* level */ + 2 /* fid */;
3514 pSMB->t2.TotalDataCount = 0;
3515 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3516 /* BB find exact max data count below from sess structure BB */
3517 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3518 pSMB->t2.MaxSetupCount = 0;
3519 pSMB->t2.Reserved = 0;
3520 pSMB->t2.Flags = 0;
3521 pSMB->t2.Timeout = 0;
3522 pSMB->t2.Reserved2 = 0;
3523 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3524 Fid) - 4);
3525 pSMB->t2.DataCount = 0;
3526 pSMB->t2.DataOffset = 0;
3527 pSMB->t2.SetupCount = 1;
3528 pSMB->t2.Reserved3 = 0;
3529 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3530 byte_count = params + 1 /* pad */ ;
3531 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3532 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3533 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3534 pSMB->Pad = 0;
3535 pSMB->Fid = netfid;
3536 pSMB->hdr.smb_buf_length += byte_count;
3537
3538 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3539 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3540 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003541 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003542 } else { /* decode response */
3543 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3544
3545 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003546 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003547 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003548 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003549 rc = -EIO; /* bad smb */
3550 } else {
3551 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3552 memcpy((char *) pFindData,
3553 (char *) &pSMBr->hdr.Protocol +
3554 data_offset,
3555 sizeof(FILE_UNIX_BASIC_INFO));
3556 }
3557 }
3558
3559 cifs_buf_release(pSMB);
3560 if (rc == -EAGAIN)
3561 goto UnixQFileInfoRetry;
3562
3563 return rc;
3564}
3565
3566int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3568 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003569 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003570 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571{
3572/* SMB_QUERY_FILE_UNIX_BASIC */
3573 TRANSACTION2_QPI_REQ *pSMB = NULL;
3574 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3575 int rc = 0;
3576 int bytes_returned = 0;
3577 int name_len;
3578 __u16 params, byte_count;
3579
Joe Perchesb6b38f72010-04-21 03:50:45 +00003580 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581UnixQPathInfoRetry:
3582 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3583 (void **) &pSMBr);
3584 if (rc)
3585 return rc;
3586
3587 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3588 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003589 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003590 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 name_len++; /* trailing null */
3592 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003593 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 name_len = strnlen(searchName, PATH_MAX);
3595 name_len++; /* trailing null */
3596 strncpy(pSMB->FileName, searchName, name_len);
3597 }
3598
Steve French50c2f752007-07-13 00:33:32 +00003599 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 pSMB->TotalDataCount = 0;
3601 pSMB->MaxParameterCount = cpu_to_le16(2);
3602 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003603 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 pSMB->MaxSetupCount = 0;
3605 pSMB->Reserved = 0;
3606 pSMB->Flags = 0;
3607 pSMB->Timeout = 0;
3608 pSMB->Reserved2 = 0;
3609 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003610 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 pSMB->DataCount = 0;
3612 pSMB->DataOffset = 0;
3613 pSMB->SetupCount = 1;
3614 pSMB->Reserved3 = 0;
3615 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3616 byte_count = params + 1 /* pad */ ;
3617 pSMB->TotalParameterCount = cpu_to_le16(params);
3618 pSMB->ParameterCount = pSMB->TotalParameterCount;
3619 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3620 pSMB->Reserved4 = 0;
3621 pSMB->hdr.smb_buf_length += byte_count;
3622 pSMB->ByteCount = cpu_to_le16(byte_count);
3623
3624 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3625 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3626 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003627 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 } else { /* decode response */
3629 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3630
3631 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003632 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003633 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003634 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 rc = -EIO; /* bad smb */
3636 } else {
3637 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3638 memcpy((char *) pFindData,
3639 (char *) &pSMBr->hdr.Protocol +
3640 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003641 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 }
3643 }
3644 cifs_buf_release(pSMB);
3645 if (rc == -EAGAIN)
3646 goto UnixQPathInfoRetry;
3647
3648 return rc;
3649}
3650
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651/* xid, tcon, searchName and codepage are input parms, rest are returned */
3652int
3653CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003654 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003656 __u16 *pnetfid,
3657 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658{
3659/* level 257 SMB_ */
3660 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3661 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003662 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 int rc = 0;
3664 int bytes_returned = 0;
3665 int name_len;
3666 __u16 params, byte_count;
3667
Joe Perchesb6b38f72010-04-21 03:50:45 +00003668 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
3670findFirstRetry:
3671 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3672 (void **) &pSMBr);
3673 if (rc)
3674 return rc;
3675
3676 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3677 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003678 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003679 PATH_MAX, nls_codepage, remap);
3680 /* We can not add the asterik earlier in case
3681 it got remapped to 0xF03A as if it were part of the
3682 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003684 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003685 pSMB->FileName[name_len+1] = 0;
3686 pSMB->FileName[name_len+2] = '*';
3687 pSMB->FileName[name_len+3] = 0;
3688 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3690 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003691 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 } else { /* BB add check for overrun of SMB buf BB */
3693 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003695 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 free buffer exit; BB */
3697 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003698 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003699 pSMB->FileName[name_len+1] = '*';
3700 pSMB->FileName[name_len+2] = 0;
3701 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 }
3703
3704 params = 12 + name_len /* includes null */ ;
3705 pSMB->TotalDataCount = 0; /* no EAs */
3706 pSMB->MaxParameterCount = cpu_to_le16(10);
3707 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3708 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3709 pSMB->MaxSetupCount = 0;
3710 pSMB->Reserved = 0;
3711 pSMB->Flags = 0;
3712 pSMB->Timeout = 0;
3713 pSMB->Reserved2 = 0;
3714 byte_count = params + 1 /* pad */ ;
3715 pSMB->TotalParameterCount = cpu_to_le16(params);
3716 pSMB->ParameterCount = pSMB->TotalParameterCount;
3717 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003718 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3719 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 pSMB->DataCount = 0;
3721 pSMB->DataOffset = 0;
3722 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3723 pSMB->Reserved3 = 0;
3724 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3725 pSMB->SearchAttributes =
3726 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3727 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003728 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3729 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 CIFS_SEARCH_RETURN_RESUME);
3731 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3732
3733 /* BB what should we set StorageType to? Does it matter? BB */
3734 pSMB->SearchStorageType = 0;
3735 pSMB->hdr.smb_buf_length += byte_count;
3736 pSMB->ByteCount = cpu_to_le16(byte_count);
3737
3738 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3739 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003740 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741
Steve French88274812006-03-09 22:21:45 +00003742 if (rc) {/* BB add logic to retry regular search if Unix search
3743 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003745 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003746
Steve French88274812006-03-09 22:21:45 +00003747 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748
3749 /* BB eventually could optimize out free and realloc of buf */
3750 /* for this case */
3751 if (rc == -EAGAIN)
3752 goto findFirstRetry;
3753 } else { /* decode response */
3754 /* BB remember to free buffer if error BB */
3755 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003756 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003757 unsigned int lnoff;
3758
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003760 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 else
Steve French4b18f2a2008-04-29 00:06:05 +00003762 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
3764 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003765 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003766 psrch_inf->srch_entries_start =
3767 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3770 le16_to_cpu(pSMBr->t2.ParameterOffset));
3771
Steve French790fe572007-07-07 19:25:05 +00003772 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003773 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 else
Steve French4b18f2a2008-04-29 00:06:05 +00003775 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Steve French50c2f752007-07-13 00:33:32 +00003777 psrch_inf->entries_in_buffer =
3778 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003779 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003781 lnoff = le16_to_cpu(parms->LastNameOffset);
3782 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3783 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003784 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003785 psrch_inf->last_entry = NULL;
3786 return rc;
3787 }
3788
Steve French0752f152008-10-07 20:03:33 +00003789 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003790 lnoff;
3791
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 *pnetfid = parms->SearchHandle;
3793 } else {
3794 cifs_buf_release(pSMB);
3795 }
3796 }
3797
3798 return rc;
3799}
3800
3801int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003802 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803{
3804 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3805 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003806 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 char *response_data;
3808 int rc = 0;
3809 int bytes_returned, name_len;
3810 __u16 params, byte_count;
3811
Joe Perchesb6b38f72010-04-21 03:50:45 +00003812 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813
Steve French4b18f2a2008-04-29 00:06:05 +00003814 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 return -ENOENT;
3816
3817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3818 (void **) &pSMBr);
3819 if (rc)
3820 return rc;
3821
Steve French50c2f752007-07-13 00:33:32 +00003822 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 byte_count = 0;
3824 pSMB->TotalDataCount = 0; /* no EAs */
3825 pSMB->MaxParameterCount = cpu_to_le16(8);
3826 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003827 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3828 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 pSMB->MaxSetupCount = 0;
3830 pSMB->Reserved = 0;
3831 pSMB->Flags = 0;
3832 pSMB->Timeout = 0;
3833 pSMB->Reserved2 = 0;
3834 pSMB->ParameterOffset = cpu_to_le16(
3835 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3836 pSMB->DataCount = 0;
3837 pSMB->DataOffset = 0;
3838 pSMB->SetupCount = 1;
3839 pSMB->Reserved3 = 0;
3840 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3841 pSMB->SearchHandle = searchHandle; /* always kept as le */
3842 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003843 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3845 pSMB->ResumeKey = psrch_inf->resume_key;
3846 pSMB->SearchFlags =
3847 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3848
3849 name_len = psrch_inf->resume_name_len;
3850 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003851 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3853 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003854 /* 14 byte parm len above enough for 2 byte null terminator */
3855 pSMB->ResumeFileName[name_len] = 0;
3856 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 } else {
3858 rc = -EINVAL;
3859 goto FNext2_err_exit;
3860 }
3861 byte_count = params + 1 /* pad */ ;
3862 pSMB->TotalParameterCount = cpu_to_le16(params);
3863 pSMB->ParameterCount = pSMB->TotalParameterCount;
3864 pSMB->hdr.smb_buf_length += byte_count;
3865 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003866
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3868 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003869 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 if (rc) {
3871 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003872 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003873 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003874 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003876 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 } else { /* decode response */
3878 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003879
Steve French790fe572007-07-07 19:25:05 +00003880 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003881 unsigned int lnoff;
3882
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 /* BB fixme add lock for file (srch_info) struct here */
3884 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003885 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 else
Steve French4b18f2a2008-04-29 00:06:05 +00003887 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 response_data = (char *) &pSMBr->hdr.Protocol +
3889 le16_to_cpu(pSMBr->t2.ParameterOffset);
3890 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3891 response_data = (char *)&pSMBr->hdr.Protocol +
3892 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003893 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003894 cifs_small_buf_release(
3895 psrch_inf->ntwrk_buf_start);
3896 else
3897 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 psrch_inf->srch_entries_start = response_data;
3899 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003900 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003901 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003902 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 else
Steve French4b18f2a2008-04-29 00:06:05 +00003904 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003905 psrch_inf->entries_in_buffer =
3906 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 psrch_inf->index_of_last_entry +=
3908 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003909 lnoff = le16_to_cpu(parms->LastNameOffset);
3910 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3911 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003912 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003913 psrch_inf->last_entry = NULL;
3914 return rc;
3915 } else
3916 psrch_inf->last_entry =
3917 psrch_inf->srch_entries_start + lnoff;
3918
Joe Perchesb6b38f72010-04-21 03:50:45 +00003919/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3920 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921
3922 /* BB fixme add unlock here */
3923 }
3924
3925 }
3926
3927 /* BB On error, should we leave previous search buf (and count and
3928 last entry fields) intact or free the previous one? */
3929
3930 /* Note: On -EAGAIN error only caller can retry on handle based calls
3931 since file handle passed in no longer valid */
3932FNext2_err_exit:
3933 if (rc != 0)
3934 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 return rc;
3936}
3937
3938int
Steve French50c2f752007-07-13 00:33:32 +00003939CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3940 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941{
3942 int rc = 0;
3943 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944
Joe Perchesb6b38f72010-04-21 03:50:45 +00003945 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3947
3948 /* no sense returning error if session restarted
3949 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003950 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 return 0;
3952 if (rc)
3953 return rc;
3954
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 pSMB->FileID = searchHandle;
3956 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003957 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003958 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003959 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003960
Steve Frencha4544342005-08-24 13:59:35 -07003961 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962
3963 /* Since session is dead, search handle closed on server already */
3964 if (rc == -EAGAIN)
3965 rc = 0;
3966
3967 return rc;
3968}
3969
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970int
3971CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003972 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003973 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003974 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975{
3976 int rc = 0;
3977 TRANSACTION2_QPI_REQ *pSMB = NULL;
3978 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3979 int name_len, bytes_returned;
3980 __u16 params, byte_count;
3981
Joe Perchesb6b38f72010-04-21 03:50:45 +00003982 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003983 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003984 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985
3986GetInodeNumberRetry:
3987 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003988 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 if (rc)
3990 return rc;
3991
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3993 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003994 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003995 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 name_len++; /* trailing null */
3997 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003998 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 name_len = strnlen(searchName, PATH_MAX);
4000 name_len++; /* trailing null */
4001 strncpy(pSMB->FileName, searchName, name_len);
4002 }
4003
4004 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4005 pSMB->TotalDataCount = 0;
4006 pSMB->MaxParameterCount = cpu_to_le16(2);
4007 /* BB find exact max data count below from sess structure BB */
4008 pSMB->MaxDataCount = cpu_to_le16(4000);
4009 pSMB->MaxSetupCount = 0;
4010 pSMB->Reserved = 0;
4011 pSMB->Flags = 0;
4012 pSMB->Timeout = 0;
4013 pSMB->Reserved2 = 0;
4014 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004015 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 pSMB->DataCount = 0;
4017 pSMB->DataOffset = 0;
4018 pSMB->SetupCount = 1;
4019 pSMB->Reserved3 = 0;
4020 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4021 byte_count = params + 1 /* pad */ ;
4022 pSMB->TotalParameterCount = cpu_to_le16(params);
4023 pSMB->ParameterCount = pSMB->TotalParameterCount;
4024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4025 pSMB->Reserved4 = 0;
4026 pSMB->hdr.smb_buf_length += byte_count;
4027 pSMB->ByteCount = cpu_to_le16(byte_count);
4028
4029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4031 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004032 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 } else {
4034 /* decode response */
4035 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4036 if (rc || (pSMBr->ByteCount < 2))
4037 /* BB also check enough total bytes returned */
4038 /* If rc should we check for EOPNOSUPP and
4039 disable the srvino flag? or in caller? */
4040 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004041 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4043 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004044 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004046 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004047 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 rc = -EIO;
4049 goto GetInodeNumOut;
4050 }
4051 pfinfo = (struct file_internal_info *)
4052 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004053 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 }
4055 }
4056GetInodeNumOut:
4057 cifs_buf_release(pSMB);
4058 if (rc == -EAGAIN)
4059 goto GetInodeNumberRetry;
4060 return rc;
4061}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062
Igor Mammedovfec45852008-05-16 13:06:30 +04004063/* parses DFS refferal V3 structure
4064 * caller is responsible for freeing target_nodes
4065 * returns:
4066 * on success - 0
4067 * on failure - errno
4068 */
4069static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004070parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004071 unsigned int *num_of_nodes,
4072 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004073 const struct nls_table *nls_codepage, int remap,
4074 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004075{
4076 int i, rc = 0;
4077 char *data_end;
4078 bool is_unicode;
4079 struct dfs_referral_level_3 *ref;
4080
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004081 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4082 is_unicode = true;
4083 else
4084 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004085 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4086
4087 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004088 cERROR(1, "num_referrals: must be at least > 0,"
4089 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004090 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004091 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004092 }
4093
4094 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004095 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004096 cERROR(1, "Referrals of V%d version are not supported,"
4097 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004098 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004099 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004100 }
4101
4102 /* get the upper boundary of the resp buffer */
4103 data_end = (char *)(&(pSMBr->PathConsumed)) +
4104 le16_to_cpu(pSMBr->t2.DataCount);
4105
Steve Frenchf19159d2010-04-21 04:12:10 +00004106 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004107 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004108 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004109
4110 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4111 *num_of_nodes, GFP_KERNEL);
4112 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004113 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004114 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004115 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004116 }
4117
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004118 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004119 for (i = 0; i < *num_of_nodes; i++) {
4120 char *temp;
4121 int max_len;
4122 struct dfs_info3_param *node = (*target_nodes)+i;
4123
Steve French0e0d2cf2009-05-01 05:27:32 +00004124 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004125 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004126 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4127 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004128 if (tmp == NULL) {
4129 rc = -ENOMEM;
4130 goto parse_DFS_referrals_exit;
4131 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004132 cifsConvertToUCS((__le16 *) tmp, searchName,
4133 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004134 node->path_consumed = cifs_ucs2_bytes(tmp,
4135 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004136 nls_codepage);
4137 kfree(tmp);
4138 } else
4139 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4140
Igor Mammedovfec45852008-05-16 13:06:30 +04004141 node->server_type = le16_to_cpu(ref->ServerType);
4142 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4143
4144 /* copy DfsPath */
4145 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4146 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004147 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4148 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004149 if (!node->path_name) {
4150 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004151 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004152 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004153
4154 /* copy link target UNC */
4155 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4156 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004157 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4158 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004159 if (!node->node_name)
4160 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004161 }
4162
Steve Frencha1fe78f2008-05-16 18:48:38 +00004163parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004164 if (rc) {
4165 free_dfs_info_array(*target_nodes, *num_of_nodes);
4166 *target_nodes = NULL;
4167 *num_of_nodes = 0;
4168 }
4169 return rc;
4170}
4171
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172int
4173CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4174 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004175 struct dfs_info3_param **target_nodes,
4176 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004177 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178{
4179/* TRANS2_GET_DFS_REFERRAL */
4180 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4181 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 int rc = 0;
4183 int bytes_returned;
4184 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004186 *num_of_nodes = 0;
4187 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188
Joe Perchesb6b38f72010-04-21 03:50:45 +00004189 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 if (ses == NULL)
4191 return -ENODEV;
4192getDFSRetry:
4193 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4194 (void **) &pSMBr);
4195 if (rc)
4196 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004197
4198 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004199 but should never be null here anyway */
4200 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 pSMB->hdr.Tid = ses->ipc_tid;
4202 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004203 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004205 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207
4208 if (ses->capabilities & CAP_UNICODE) {
4209 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4210 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004211 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004212 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 name_len++; /* trailing null */
4214 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004215 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 name_len = strnlen(searchName, PATH_MAX);
4217 name_len++; /* trailing null */
4218 strncpy(pSMB->RequestFileName, searchName, name_len);
4219 }
4220
Steve French790fe572007-07-07 19:25:05 +00004221 if (ses->server) {
4222 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004223 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4224 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4225 }
4226
Steve French50c2f752007-07-13 00:33:32 +00004227 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004228
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 params = 2 /* level */ + name_len /*includes null */ ;
4230 pSMB->TotalDataCount = 0;
4231 pSMB->DataCount = 0;
4232 pSMB->DataOffset = 0;
4233 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004234 /* BB find exact max SMB PDU from sess structure BB */
4235 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 pSMB->MaxSetupCount = 0;
4237 pSMB->Reserved = 0;
4238 pSMB->Flags = 0;
4239 pSMB->Timeout = 0;
4240 pSMB->Reserved2 = 0;
4241 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004242 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 pSMB->SetupCount = 1;
4244 pSMB->Reserved3 = 0;
4245 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4246 byte_count = params + 3 /* pad */ ;
4247 pSMB->ParameterCount = cpu_to_le16(params);
4248 pSMB->TotalParameterCount = pSMB->ParameterCount;
4249 pSMB->MaxReferralLevel = cpu_to_le16(3);
4250 pSMB->hdr.smb_buf_length += byte_count;
4251 pSMB->ByteCount = cpu_to_le16(byte_count);
4252
4253 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4254 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4255 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004256 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004257 goto GetDFSRefExit;
4258 }
4259 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004261 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004262 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004263 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004264 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004266
Joe Perchesb6b38f72010-04-21 03:50:45 +00004267 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Igor Mammedovfec45852008-05-16 13:06:30 +04004268 pSMBr->ByteCount,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004269 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004270
4271 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004272 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004273 target_nodes, nls_codepage, remap,
4274 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004275
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004277 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278
4279 if (rc == -EAGAIN)
4280 goto getDFSRetry;
4281
4282 return rc;
4283}
4284
Steve French20962432005-09-21 22:05:57 -07004285/* Query File System Info such as free space to old servers such as Win 9x */
4286int
4287SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4288{
4289/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4290 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4291 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4292 FILE_SYSTEM_ALLOC_INFO *response_data;
4293 int rc = 0;
4294 int bytes_returned = 0;
4295 __u16 params, byte_count;
4296
Joe Perchesb6b38f72010-04-21 03:50:45 +00004297 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004298oldQFSInfoRetry:
4299 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4300 (void **) &pSMBr);
4301 if (rc)
4302 return rc;
Steve French20962432005-09-21 22:05:57 -07004303
4304 params = 2; /* level */
4305 pSMB->TotalDataCount = 0;
4306 pSMB->MaxParameterCount = cpu_to_le16(2);
4307 pSMB->MaxDataCount = cpu_to_le16(1000);
4308 pSMB->MaxSetupCount = 0;
4309 pSMB->Reserved = 0;
4310 pSMB->Flags = 0;
4311 pSMB->Timeout = 0;
4312 pSMB->Reserved2 = 0;
4313 byte_count = params + 1 /* pad */ ;
4314 pSMB->TotalParameterCount = cpu_to_le16(params);
4315 pSMB->ParameterCount = pSMB->TotalParameterCount;
4316 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4317 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4318 pSMB->DataCount = 0;
4319 pSMB->DataOffset = 0;
4320 pSMB->SetupCount = 1;
4321 pSMB->Reserved3 = 0;
4322 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4323 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4324 pSMB->hdr.smb_buf_length += byte_count;
4325 pSMB->ByteCount = cpu_to_le16(byte_count);
4326
4327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4329 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004330 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004331 } else { /* decode response */
4332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4333
4334 if (rc || (pSMBr->ByteCount < 18))
4335 rc = -EIO; /* bad smb */
4336 else {
4337 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004338 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4339 pSMBr->ByteCount, data_offset);
Steve French20962432005-09-21 22:05:57 -07004340
Steve French50c2f752007-07-13 00:33:32 +00004341 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004342 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4343 FSData->f_bsize =
4344 le16_to_cpu(response_data->BytesPerSector) *
4345 le32_to_cpu(response_data->
4346 SectorsPerAllocationUnit);
4347 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004348 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004349 FSData->f_bfree = FSData->f_bavail =
4350 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004351 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4352 (unsigned long long)FSData->f_blocks,
4353 (unsigned long long)FSData->f_bfree,
4354 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004355 }
4356 }
4357 cifs_buf_release(pSMB);
4358
4359 if (rc == -EAGAIN)
4360 goto oldQFSInfoRetry;
4361
4362 return rc;
4363}
4364
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365int
Steve French737b7582005-04-28 22:41:06 -07004366CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367{
4368/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4369 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4370 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4371 FILE_SYSTEM_INFO *response_data;
4372 int rc = 0;
4373 int bytes_returned = 0;
4374 __u16 params, byte_count;
4375
Joe Perchesb6b38f72010-04-21 03:50:45 +00004376 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377QFSInfoRetry:
4378 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4379 (void **) &pSMBr);
4380 if (rc)
4381 return rc;
4382
4383 params = 2; /* level */
4384 pSMB->TotalDataCount = 0;
4385 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004386 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 pSMB->MaxSetupCount = 0;
4388 pSMB->Reserved = 0;
4389 pSMB->Flags = 0;
4390 pSMB->Timeout = 0;
4391 pSMB->Reserved2 = 0;
4392 byte_count = params + 1 /* pad */ ;
4393 pSMB->TotalParameterCount = cpu_to_le16(params);
4394 pSMB->ParameterCount = pSMB->TotalParameterCount;
4395 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004396 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 pSMB->DataCount = 0;
4398 pSMB->DataOffset = 0;
4399 pSMB->SetupCount = 1;
4400 pSMB->Reserved3 = 0;
4401 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4402 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4403 pSMB->hdr.smb_buf_length += byte_count;
4404 pSMB->ByteCount = cpu_to_le16(byte_count);
4405
4406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4408 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004409 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004411 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412
Steve French20962432005-09-21 22:05:57 -07004413 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 rc = -EIO; /* bad smb */
4415 else {
4416 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
4418 response_data =
4419 (FILE_SYSTEM_INFO
4420 *) (((char *) &pSMBr->hdr.Protocol) +
4421 data_offset);
4422 FSData->f_bsize =
4423 le32_to_cpu(response_data->BytesPerSector) *
4424 le32_to_cpu(response_data->
4425 SectorsPerAllocationUnit);
4426 FSData->f_blocks =
4427 le64_to_cpu(response_data->TotalAllocationUnits);
4428 FSData->f_bfree = FSData->f_bavail =
4429 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004430 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4431 (unsigned long long)FSData->f_blocks,
4432 (unsigned long long)FSData->f_bfree,
4433 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 }
4435 }
4436 cifs_buf_release(pSMB);
4437
4438 if (rc == -EAGAIN)
4439 goto QFSInfoRetry;
4440
4441 return rc;
4442}
4443
4444int
Steve French737b7582005-04-28 22:41:06 -07004445CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446{
4447/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4448 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4449 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4450 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4451 int rc = 0;
4452 int bytes_returned = 0;
4453 __u16 params, byte_count;
4454
Joe Perchesb6b38f72010-04-21 03:50:45 +00004455 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456QFSAttributeRetry:
4457 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4458 (void **) &pSMBr);
4459 if (rc)
4460 return rc;
4461
4462 params = 2; /* level */
4463 pSMB->TotalDataCount = 0;
4464 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004465 /* BB find exact max SMB PDU from sess structure BB */
4466 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 pSMB->MaxSetupCount = 0;
4468 pSMB->Reserved = 0;
4469 pSMB->Flags = 0;
4470 pSMB->Timeout = 0;
4471 pSMB->Reserved2 = 0;
4472 byte_count = params + 1 /* pad */ ;
4473 pSMB->TotalParameterCount = cpu_to_le16(params);
4474 pSMB->ParameterCount = pSMB->TotalParameterCount;
4475 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004476 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 pSMB->DataCount = 0;
4478 pSMB->DataOffset = 0;
4479 pSMB->SetupCount = 1;
4480 pSMB->Reserved3 = 0;
4481 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4482 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4483 pSMB->hdr.smb_buf_length += byte_count;
4484 pSMB->ByteCount = cpu_to_le16(byte_count);
4485
4486 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4487 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4488 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004489 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 } else { /* decode response */
4491 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4492
Steve French50c2f752007-07-13 00:33:32 +00004493 if (rc || (pSMBr->ByteCount < 13)) {
4494 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 rc = -EIO; /* bad smb */
4496 } else {
4497 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4498 response_data =
4499 (FILE_SYSTEM_ATTRIBUTE_INFO
4500 *) (((char *) &pSMBr->hdr.Protocol) +
4501 data_offset);
4502 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004503 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 }
4505 }
4506 cifs_buf_release(pSMB);
4507
4508 if (rc == -EAGAIN)
4509 goto QFSAttributeRetry;
4510
4511 return rc;
4512}
4513
4514int
Steve French737b7582005-04-28 22:41:06 -07004515CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516{
4517/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4518 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4519 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4520 FILE_SYSTEM_DEVICE_INFO *response_data;
4521 int rc = 0;
4522 int bytes_returned = 0;
4523 __u16 params, byte_count;
4524
Joe Perchesb6b38f72010-04-21 03:50:45 +00004525 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526QFSDeviceRetry:
4527 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4528 (void **) &pSMBr);
4529 if (rc)
4530 return rc;
4531
4532 params = 2; /* level */
4533 pSMB->TotalDataCount = 0;
4534 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004535 /* BB find exact max SMB PDU from sess structure BB */
4536 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 pSMB->MaxSetupCount = 0;
4538 pSMB->Reserved = 0;
4539 pSMB->Flags = 0;
4540 pSMB->Timeout = 0;
4541 pSMB->Reserved2 = 0;
4542 byte_count = params + 1 /* pad */ ;
4543 pSMB->TotalParameterCount = cpu_to_le16(params);
4544 pSMB->ParameterCount = pSMB->TotalParameterCount;
4545 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004546 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547
4548 pSMB->DataCount = 0;
4549 pSMB->DataOffset = 0;
4550 pSMB->SetupCount = 1;
4551 pSMB->Reserved3 = 0;
4552 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4553 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4554 pSMB->hdr.smb_buf_length += byte_count;
4555 pSMB->ByteCount = cpu_to_le16(byte_count);
4556
4557 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4558 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4559 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004560 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 } else { /* decode response */
4562 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4563
Steve French630f3f0c2007-10-25 21:17:17 +00004564 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 rc = -EIO; /* bad smb */
4566 else {
4567 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4568 response_data =
Steve French737b7582005-04-28 22:41:06 -07004569 (FILE_SYSTEM_DEVICE_INFO *)
4570 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 data_offset);
4572 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004573 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 }
4575 }
4576 cifs_buf_release(pSMB);
4577
4578 if (rc == -EAGAIN)
4579 goto QFSDeviceRetry;
4580
4581 return rc;
4582}
4583
4584int
Steve French737b7582005-04-28 22:41:06 -07004585CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586{
4587/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4588 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4589 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4590 FILE_SYSTEM_UNIX_INFO *response_data;
4591 int rc = 0;
4592 int bytes_returned = 0;
4593 __u16 params, byte_count;
4594
Joe Perchesb6b38f72010-04-21 03:50:45 +00004595 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004597 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4598 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 if (rc)
4600 return rc;
4601
4602 params = 2; /* level */
4603 pSMB->TotalDataCount = 0;
4604 pSMB->DataCount = 0;
4605 pSMB->DataOffset = 0;
4606 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004607 /* BB find exact max SMB PDU from sess structure BB */
4608 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 pSMB->MaxSetupCount = 0;
4610 pSMB->Reserved = 0;
4611 pSMB->Flags = 0;
4612 pSMB->Timeout = 0;
4613 pSMB->Reserved2 = 0;
4614 byte_count = params + 1 /* pad */ ;
4615 pSMB->ParameterCount = cpu_to_le16(params);
4616 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004617 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4618 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 pSMB->SetupCount = 1;
4620 pSMB->Reserved3 = 0;
4621 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4622 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4623 pSMB->hdr.smb_buf_length += byte_count;
4624 pSMB->ByteCount = cpu_to_le16(byte_count);
4625
4626 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4627 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4628 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004629 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 } else { /* decode response */
4631 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4632
4633 if (rc || (pSMBr->ByteCount < 13)) {
4634 rc = -EIO; /* bad smb */
4635 } else {
4636 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4637 response_data =
4638 (FILE_SYSTEM_UNIX_INFO
4639 *) (((char *) &pSMBr->hdr.Protocol) +
4640 data_offset);
4641 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004642 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 }
4644 }
4645 cifs_buf_release(pSMB);
4646
4647 if (rc == -EAGAIN)
4648 goto QFSUnixRetry;
4649
4650
4651 return rc;
4652}
4653
Jeremy Allisonac670552005-06-22 17:26:35 -07004654int
Steve French45abc6e2005-06-23 13:42:03 -05004655CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004656{
4657/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4658 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4659 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4660 int rc = 0;
4661 int bytes_returned = 0;
4662 __u16 params, param_offset, offset, byte_count;
4663
Joe Perchesb6b38f72010-04-21 03:50:45 +00004664 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004665SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004666 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004667 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4668 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004669 if (rc)
4670 return rc;
4671
4672 params = 4; /* 2 bytes zero followed by info level. */
4673 pSMB->MaxSetupCount = 0;
4674 pSMB->Reserved = 0;
4675 pSMB->Flags = 0;
4676 pSMB->Timeout = 0;
4677 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004678 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4679 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004680 offset = param_offset + params;
4681
4682 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004683 /* BB find exact max SMB PDU from sess structure BB */
4684 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004685 pSMB->SetupCount = 1;
4686 pSMB->Reserved3 = 0;
4687 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4688 byte_count = 1 /* pad */ + params + 12;
4689
4690 pSMB->DataCount = cpu_to_le16(12);
4691 pSMB->ParameterCount = cpu_to_le16(params);
4692 pSMB->TotalDataCount = pSMB->DataCount;
4693 pSMB->TotalParameterCount = pSMB->ParameterCount;
4694 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4695 pSMB->DataOffset = cpu_to_le16(offset);
4696
4697 /* Params. */
4698 pSMB->FileNum = 0;
4699 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4700
4701 /* Data. */
4702 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4703 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4704 pSMB->ClientUnixCap = cpu_to_le64(cap);
4705
4706 pSMB->hdr.smb_buf_length += byte_count;
4707 pSMB->ByteCount = cpu_to_le16(byte_count);
4708
4709 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4710 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4711 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004712 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004713 } else { /* decode response */
4714 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004715 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004716 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004717 }
4718 cifs_buf_release(pSMB);
4719
4720 if (rc == -EAGAIN)
4721 goto SETFSUnixRetry;
4722
4723 return rc;
4724}
4725
4726
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727
4728int
4729CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004730 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731{
4732/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4733 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4734 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4735 FILE_SYSTEM_POSIX_INFO *response_data;
4736 int rc = 0;
4737 int bytes_returned = 0;
4738 __u16 params, byte_count;
4739
Joe Perchesb6b38f72010-04-21 03:50:45 +00004740 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741QFSPosixRetry:
4742 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4743 (void **) &pSMBr);
4744 if (rc)
4745 return rc;
4746
4747 params = 2; /* level */
4748 pSMB->TotalDataCount = 0;
4749 pSMB->DataCount = 0;
4750 pSMB->DataOffset = 0;
4751 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004752 /* BB find exact max SMB PDU from sess structure BB */
4753 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 pSMB->MaxSetupCount = 0;
4755 pSMB->Reserved = 0;
4756 pSMB->Flags = 0;
4757 pSMB->Timeout = 0;
4758 pSMB->Reserved2 = 0;
4759 byte_count = params + 1 /* pad */ ;
4760 pSMB->ParameterCount = cpu_to_le16(params);
4761 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004762 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4763 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 pSMB->SetupCount = 1;
4765 pSMB->Reserved3 = 0;
4766 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4767 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4768 pSMB->hdr.smb_buf_length += byte_count;
4769 pSMB->ByteCount = cpu_to_le16(byte_count);
4770
4771 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4772 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4773 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004774 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 } else { /* decode response */
4776 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4777
4778 if (rc || (pSMBr->ByteCount < 13)) {
4779 rc = -EIO; /* bad smb */
4780 } else {
4781 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4782 response_data =
4783 (FILE_SYSTEM_POSIX_INFO
4784 *) (((char *) &pSMBr->hdr.Protocol) +
4785 data_offset);
4786 FSData->f_bsize =
4787 le32_to_cpu(response_data->BlockSize);
4788 FSData->f_blocks =
4789 le64_to_cpu(response_data->TotalBlocks);
4790 FSData->f_bfree =
4791 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004792 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 FSData->f_bavail = FSData->f_bfree;
4794 } else {
4795 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004796 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 }
Steve French790fe572007-07-07 19:25:05 +00004798 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004800 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004801 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004803 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 }
4805 }
4806 cifs_buf_release(pSMB);
4807
4808 if (rc == -EAGAIN)
4809 goto QFSPosixRetry;
4810
4811 return rc;
4812}
4813
4814
Steve French50c2f752007-07-13 00:33:32 +00004815/* We can not use write of zero bytes trick to
4816 set file size due to need for large file support. Also note that
4817 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 routine which is only needed to work around a sharing violation bug
4819 in Samba which this routine can run into */
4820
4821int
4822CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004823 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004824 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825{
4826 struct smb_com_transaction2_spi_req *pSMB = NULL;
4827 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4828 struct file_end_of_file_info *parm_data;
4829 int name_len;
4830 int rc = 0;
4831 int bytes_returned = 0;
4832 __u16 params, byte_count, data_count, param_offset, offset;
4833
Joe Perchesb6b38f72010-04-21 03:50:45 +00004834 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835SetEOFRetry:
4836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4837 (void **) &pSMBr);
4838 if (rc)
4839 return rc;
4840
4841 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4842 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004843 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004844 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 name_len++; /* trailing null */
4846 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004847 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 name_len = strnlen(fileName, PATH_MAX);
4849 name_len++; /* trailing null */
4850 strncpy(pSMB->FileName, fileName, name_len);
4851 }
4852 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004853 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004855 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 pSMB->MaxSetupCount = 0;
4857 pSMB->Reserved = 0;
4858 pSMB->Flags = 0;
4859 pSMB->Timeout = 0;
4860 pSMB->Reserved2 = 0;
4861 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004862 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004864 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004865 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4866 pSMB->InformationLevel =
4867 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4868 else
4869 pSMB->InformationLevel =
4870 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4871 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4873 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004874 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 else
4876 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004877 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 }
4879
4880 parm_data =
4881 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4882 offset);
4883 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4884 pSMB->DataOffset = cpu_to_le16(offset);
4885 pSMB->SetupCount = 1;
4886 pSMB->Reserved3 = 0;
4887 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4888 byte_count = 3 /* pad */ + params + data_count;
4889 pSMB->DataCount = cpu_to_le16(data_count);
4890 pSMB->TotalDataCount = pSMB->DataCount;
4891 pSMB->ParameterCount = cpu_to_le16(params);
4892 pSMB->TotalParameterCount = pSMB->ParameterCount;
4893 pSMB->Reserved4 = 0;
4894 pSMB->hdr.smb_buf_length += byte_count;
4895 parm_data->FileSize = cpu_to_le64(size);
4896 pSMB->ByteCount = cpu_to_le16(byte_count);
4897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004899 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004900 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901
4902 cifs_buf_release(pSMB);
4903
4904 if (rc == -EAGAIN)
4905 goto SetEOFRetry;
4906
4907 return rc;
4908}
4909
4910int
Steve French50c2f752007-07-13 00:33:32 +00004911CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004912 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913{
4914 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 char *data_offset;
4916 struct file_end_of_file_info *parm_data;
4917 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 __u16 params, param_offset, offset, byte_count, count;
4919
Joe Perchesb6b38f72010-04-21 03:50:45 +00004920 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4921 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004922 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4923
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 if (rc)
4925 return rc;
4926
4927 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4928 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004929
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930 params = 6;
4931 pSMB->MaxSetupCount = 0;
4932 pSMB->Reserved = 0;
4933 pSMB->Flags = 0;
4934 pSMB->Timeout = 0;
4935 pSMB->Reserved2 = 0;
4936 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4937 offset = param_offset + params;
4938
Steve French50c2f752007-07-13 00:33:32 +00004939 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940
4941 count = sizeof(struct file_end_of_file_info);
4942 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004943 /* BB find exact max SMB PDU from sess structure BB */
4944 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 pSMB->SetupCount = 1;
4946 pSMB->Reserved3 = 0;
4947 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4948 byte_count = 3 /* pad */ + params + count;
4949 pSMB->DataCount = cpu_to_le16(count);
4950 pSMB->ParameterCount = cpu_to_le16(params);
4951 pSMB->TotalDataCount = pSMB->DataCount;
4952 pSMB->TotalParameterCount = pSMB->ParameterCount;
4953 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4954 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004955 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4956 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 pSMB->DataOffset = cpu_to_le16(offset);
4958 parm_data->FileSize = cpu_to_le64(size);
4959 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004960 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4962 pSMB->InformationLevel =
4963 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4964 else
4965 pSMB->InformationLevel =
4966 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004967 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4969 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004970 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 else
4972 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004973 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 }
4975 pSMB->Reserved4 = 0;
4976 pSMB->hdr.smb_buf_length += byte_count;
4977 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004978 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004980 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 }
4982
Steve French50c2f752007-07-13 00:33:32 +00004983 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 since file handle passed in no longer valid */
4985
4986 return rc;
4987}
4988
Steve French50c2f752007-07-13 00:33:32 +00004989/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 an open handle, rather than by pathname - this is awkward due to
4991 potential access conflicts on the open, but it is unavoidable for these
4992 old servers since the only other choice is to go from 100 nanosecond DCE
4993 time and resort to the original setpathinfo level which takes the ancient
4994 DOS time format with 2 second granularity */
4995int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004996CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4997 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998{
4999 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 char *data_offset;
5001 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002 __u16 params, param_offset, offset, byte_count, count;
5003
Joe Perchesb6b38f72010-04-21 03:50:45 +00005004 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005005 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 if (rc)
5008 return rc;
5009
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005010 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5011 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005012
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 params = 6;
5014 pSMB->MaxSetupCount = 0;
5015 pSMB->Reserved = 0;
5016 pSMB->Flags = 0;
5017 pSMB->Timeout = 0;
5018 pSMB->Reserved2 = 0;
5019 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5020 offset = param_offset + params;
5021
Steve French50c2f752007-07-13 00:33:32 +00005022 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023
Steve French26f57362007-08-30 22:09:15 +00005024 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005026 /* BB find max SMB PDU from sess */
5027 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 pSMB->SetupCount = 1;
5029 pSMB->Reserved3 = 0;
5030 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5031 byte_count = 3 /* pad */ + params + count;
5032 pSMB->DataCount = cpu_to_le16(count);
5033 pSMB->ParameterCount = cpu_to_le16(params);
5034 pSMB->TotalDataCount = pSMB->DataCount;
5035 pSMB->TotalParameterCount = pSMB->ParameterCount;
5036 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5037 pSMB->DataOffset = cpu_to_le16(offset);
5038 pSMB->Fid = fid;
5039 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5041 else
5042 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5043 pSMB->Reserved4 = 0;
5044 pSMB->hdr.smb_buf_length += byte_count;
5045 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005046 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005047 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005048 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005049 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050
Steve French50c2f752007-07-13 00:33:32 +00005051 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 since file handle passed in no longer valid */
5053
5054 return rc;
5055}
5056
Jeff Layton6d22f092008-09-23 11:48:35 -04005057int
5058CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5059 bool delete_file, __u16 fid, __u32 pid_of_opener)
5060{
5061 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5062 char *data_offset;
5063 int rc = 0;
5064 __u16 params, param_offset, offset, byte_count, count;
5065
Joe Perchesb6b38f72010-04-21 03:50:45 +00005066 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005067 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5068
5069 if (rc)
5070 return rc;
5071
5072 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5073 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5074
5075 params = 6;
5076 pSMB->MaxSetupCount = 0;
5077 pSMB->Reserved = 0;
5078 pSMB->Flags = 0;
5079 pSMB->Timeout = 0;
5080 pSMB->Reserved2 = 0;
5081 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5082 offset = param_offset + params;
5083
5084 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5085
5086 count = 1;
5087 pSMB->MaxParameterCount = cpu_to_le16(2);
5088 /* BB find max SMB PDU from sess */
5089 pSMB->MaxDataCount = cpu_to_le16(1000);
5090 pSMB->SetupCount = 1;
5091 pSMB->Reserved3 = 0;
5092 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5093 byte_count = 3 /* pad */ + params + count;
5094 pSMB->DataCount = cpu_to_le16(count);
5095 pSMB->ParameterCount = cpu_to_le16(params);
5096 pSMB->TotalDataCount = pSMB->DataCount;
5097 pSMB->TotalParameterCount = pSMB->ParameterCount;
5098 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5099 pSMB->DataOffset = cpu_to_le16(offset);
5100 pSMB->Fid = fid;
5101 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5102 pSMB->Reserved4 = 0;
5103 pSMB->hdr.smb_buf_length += byte_count;
5104 pSMB->ByteCount = cpu_to_le16(byte_count);
5105 *data_offset = delete_file ? 1 : 0;
5106 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5107 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005108 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005109
5110 return rc;
5111}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112
5113int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005114CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5115 const char *fileName, const FILE_BASIC_INFO *data,
5116 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117{
5118 TRANSACTION2_SPI_REQ *pSMB = NULL;
5119 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5120 int name_len;
5121 int rc = 0;
5122 int bytes_returned = 0;
5123 char *data_offset;
5124 __u16 params, param_offset, offset, byte_count, count;
5125
Joe Perchesb6b38f72010-04-21 03:50:45 +00005126 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127
5128SetTimesRetry:
5129 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5130 (void **) &pSMBr);
5131 if (rc)
5132 return rc;
5133
5134 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5135 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005136 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005137 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 name_len++; /* trailing null */
5139 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005140 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 name_len = strnlen(fileName, PATH_MAX);
5142 name_len++; /* trailing null */
5143 strncpy(pSMB->FileName, fileName, name_len);
5144 }
5145
5146 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005147 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005149 /* BB find max SMB PDU from sess structure BB */
5150 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 pSMB->MaxSetupCount = 0;
5152 pSMB->Reserved = 0;
5153 pSMB->Flags = 0;
5154 pSMB->Timeout = 0;
5155 pSMB->Reserved2 = 0;
5156 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005157 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 offset = param_offset + params;
5159 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5160 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5161 pSMB->DataOffset = cpu_to_le16(offset);
5162 pSMB->SetupCount = 1;
5163 pSMB->Reserved3 = 0;
5164 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5165 byte_count = 3 /* pad */ + params + count;
5166
5167 pSMB->DataCount = cpu_to_le16(count);
5168 pSMB->ParameterCount = cpu_to_le16(params);
5169 pSMB->TotalDataCount = pSMB->DataCount;
5170 pSMB->TotalParameterCount = pSMB->ParameterCount;
5171 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5172 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5173 else
5174 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5175 pSMB->Reserved4 = 0;
5176 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005177 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 pSMB->ByteCount = cpu_to_le16(byte_count);
5179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005181 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005182 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183
5184 cifs_buf_release(pSMB);
5185
5186 if (rc == -EAGAIN)
5187 goto SetTimesRetry;
5188
5189 return rc;
5190}
5191
5192/* Can not be used to set time stamps yet (due to old DOS time format) */
5193/* Can be used to set attributes */
5194#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5195 handling it anyway and NT4 was what we thought it would be needed for
5196 Do not delete it until we prove whether needed for Win9x though */
5197int
5198CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5199 __u16 dos_attrs, const struct nls_table *nls_codepage)
5200{
5201 SETATTR_REQ *pSMB = NULL;
5202 SETATTR_RSP *pSMBr = NULL;
5203 int rc = 0;
5204 int bytes_returned;
5205 int name_len;
5206
Joe Perchesb6b38f72010-04-21 03:50:45 +00005207 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208
5209SetAttrLgcyRetry:
5210 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5211 (void **) &pSMBr);
5212 if (rc)
5213 return rc;
5214
5215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5216 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005217 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 PATH_MAX, nls_codepage);
5219 name_len++; /* trailing null */
5220 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005221 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 name_len = strnlen(fileName, PATH_MAX);
5223 name_len++; /* trailing null */
5224 strncpy(pSMB->fileName, fileName, name_len);
5225 }
5226 pSMB->attr = cpu_to_le16(dos_attrs);
5227 pSMB->BufferFormat = 0x04;
5228 pSMB->hdr.smb_buf_length += name_len + 1;
5229 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5231 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005232 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005233 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234
5235 cifs_buf_release(pSMB);
5236
5237 if (rc == -EAGAIN)
5238 goto SetAttrLgcyRetry;
5239
5240 return rc;
5241}
5242#endif /* temporarily unneeded SetAttr legacy function */
5243
Jeff Layton654cf142009-07-09 20:02:49 -04005244static void
5245cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5246 const struct cifs_unix_set_info_args *args)
5247{
5248 u64 mode = args->mode;
5249
5250 /*
5251 * Samba server ignores set of file size to zero due to bugs in some
5252 * older clients, but we should be precise - we use SetFileSize to
5253 * set file size and do not want to truncate file size to zero
5254 * accidently as happened on one Samba server beta by putting
5255 * zero instead of -1 here
5256 */
5257 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5258 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5259 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5260 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5261 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5262 data_offset->Uid = cpu_to_le64(args->uid);
5263 data_offset->Gid = cpu_to_le64(args->gid);
5264 /* better to leave device as zero when it is */
5265 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5266 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5267 data_offset->Permissions = cpu_to_le64(mode);
5268
5269 if (S_ISREG(mode))
5270 data_offset->Type = cpu_to_le32(UNIX_FILE);
5271 else if (S_ISDIR(mode))
5272 data_offset->Type = cpu_to_le32(UNIX_DIR);
5273 else if (S_ISLNK(mode))
5274 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5275 else if (S_ISCHR(mode))
5276 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5277 else if (S_ISBLK(mode))
5278 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5279 else if (S_ISFIFO(mode))
5280 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5281 else if (S_ISSOCK(mode))
5282 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5283}
5284
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005286CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5287 const struct cifs_unix_set_info_args *args,
5288 u16 fid, u32 pid_of_opener)
5289{
5290 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5291 FILE_UNIX_BASIC_INFO *data_offset;
5292 int rc = 0;
5293 u16 params, param_offset, offset, byte_count, count;
5294
Joe Perchesb6b38f72010-04-21 03:50:45 +00005295 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005296 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5297
5298 if (rc)
5299 return rc;
5300
5301 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5302 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5303
5304 params = 6;
5305 pSMB->MaxSetupCount = 0;
5306 pSMB->Reserved = 0;
5307 pSMB->Flags = 0;
5308 pSMB->Timeout = 0;
5309 pSMB->Reserved2 = 0;
5310 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5311 offset = param_offset + params;
5312
5313 data_offset = (FILE_UNIX_BASIC_INFO *)
5314 ((char *)(&pSMB->hdr.Protocol) + offset);
5315 count = sizeof(FILE_UNIX_BASIC_INFO);
5316
5317 pSMB->MaxParameterCount = cpu_to_le16(2);
5318 /* BB find max SMB PDU from sess */
5319 pSMB->MaxDataCount = cpu_to_le16(1000);
5320 pSMB->SetupCount = 1;
5321 pSMB->Reserved3 = 0;
5322 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5323 byte_count = 3 /* pad */ + params + count;
5324 pSMB->DataCount = cpu_to_le16(count);
5325 pSMB->ParameterCount = cpu_to_le16(params);
5326 pSMB->TotalDataCount = pSMB->DataCount;
5327 pSMB->TotalParameterCount = pSMB->ParameterCount;
5328 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5329 pSMB->DataOffset = cpu_to_le16(offset);
5330 pSMB->Fid = fid;
5331 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5332 pSMB->Reserved4 = 0;
5333 pSMB->hdr.smb_buf_length += byte_count;
5334 pSMB->ByteCount = cpu_to_le16(byte_count);
5335
5336 cifs_fill_unix_set_info(data_offset, args);
5337
5338 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5339 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005340 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005341
5342 /* Note: On -EAGAIN error only caller can retry on handle based calls
5343 since file handle passed in no longer valid */
5344
5345 return rc;
5346}
5347
5348int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005349CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5350 const struct cifs_unix_set_info_args *args,
5351 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352{
5353 TRANSACTION2_SPI_REQ *pSMB = NULL;
5354 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5355 int name_len;
5356 int rc = 0;
5357 int bytes_returned = 0;
5358 FILE_UNIX_BASIC_INFO *data_offset;
5359 __u16 params, param_offset, offset, count, byte_count;
5360
Joe Perchesb6b38f72010-04-21 03:50:45 +00005361 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362setPermsRetry:
5363 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5364 (void **) &pSMBr);
5365 if (rc)
5366 return rc;
5367
5368 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5369 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005370 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005371 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 name_len++; /* trailing null */
5373 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005374 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 name_len = strnlen(fileName, PATH_MAX);
5376 name_len++; /* trailing null */
5377 strncpy(pSMB->FileName, fileName, name_len);
5378 }
5379
5380 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005381 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005383 /* BB find max SMB PDU from sess structure BB */
5384 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 pSMB->MaxSetupCount = 0;
5386 pSMB->Reserved = 0;
5387 pSMB->Flags = 0;
5388 pSMB->Timeout = 0;
5389 pSMB->Reserved2 = 0;
5390 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005391 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 offset = param_offset + params;
5393 data_offset =
5394 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5395 offset);
5396 memset(data_offset, 0, count);
5397 pSMB->DataOffset = cpu_to_le16(offset);
5398 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5399 pSMB->SetupCount = 1;
5400 pSMB->Reserved3 = 0;
5401 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5402 byte_count = 3 /* pad */ + params + count;
5403 pSMB->ParameterCount = cpu_to_le16(params);
5404 pSMB->DataCount = cpu_to_le16(count);
5405 pSMB->TotalParameterCount = pSMB->ParameterCount;
5406 pSMB->TotalDataCount = pSMB->DataCount;
5407 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5408 pSMB->Reserved4 = 0;
5409 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005410
Jeff Layton654cf142009-07-09 20:02:49 -04005411 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412
5413 pSMB->ByteCount = cpu_to_le16(byte_count);
5414 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5415 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005416 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005417 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
Steve French0d817bc2008-05-22 02:02:03 +00005419 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 if (rc == -EAGAIN)
5421 goto setPermsRetry;
5422 return rc;
5423}
5424
Steve French50c2f752007-07-13 00:33:32 +00005425int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005426 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005427 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005428 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429{
5430 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005431 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5432 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005433 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 int bytes_returned;
5435
Joe Perchesb6b38f72010-04-21 03:50:45 +00005436 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005438 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 if (rc)
5440 return rc;
5441
5442 pSMB->TotalParameterCount = 0 ;
5443 pSMB->TotalDataCount = 0;
5444 pSMB->MaxParameterCount = cpu_to_le32(2);
5445 /* BB find exact data count max from sess structure BB */
5446 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005447/* BB VERIFY verify which is correct for above BB */
5448 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5449 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5450
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 pSMB->MaxSetupCount = 4;
5452 pSMB->Reserved = 0;
5453 pSMB->ParameterOffset = 0;
5454 pSMB->DataCount = 0;
5455 pSMB->DataOffset = 0;
5456 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5457 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5458 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005459 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5461 pSMB->Reserved2 = 0;
5462 pSMB->CompletionFilter = cpu_to_le32(filter);
5463 pSMB->Fid = netfid; /* file handle always le */
5464 pSMB->ByteCount = 0;
5465
5466 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005467 (struct smb_hdr *)pSMBr, &bytes_returned,
5468 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005470 cFYI(1, "Error in Notify = %d", rc);
Steve Frenchff5dbd92005-08-24 17:10:36 -07005471 } else {
5472 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005473 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005474 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005475 sizeof(struct dir_notify_req),
5476 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005477 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005478 dnotify_req->Pid = pSMB->hdr.Pid;
5479 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5480 dnotify_req->Mid = pSMB->hdr.Mid;
5481 dnotify_req->Tid = pSMB->hdr.Tid;
5482 dnotify_req->Uid = pSMB->hdr.Uid;
5483 dnotify_req->netfid = netfid;
5484 dnotify_req->pfile = pfile;
5485 dnotify_req->filter = filter;
5486 dnotify_req->multishot = multishot;
5487 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005488 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005489 &GlobalDnotifyReqList);
5490 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005491 } else
Steve French47c786e2005-10-11 20:03:18 -07005492 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 }
5494 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005495 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496}
Jeff Layton31c05192010-02-10 16:18:26 -05005497
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005499/*
5500 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5501 * function used by listxattr and getxattr type calls. When ea_name is set,
5502 * it looks for that attribute name and stuffs that value into the EAData
5503 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5504 * buffer. In both cases, the return value is either the length of the
5505 * resulting data or a negative error code. If EAData is a NULL pointer then
5506 * the data isn't copied to it, but the length is returned.
5507 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508ssize_t
5509CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005510 const unsigned char *searchName, const unsigned char *ea_name,
5511 char *EAData, size_t buf_size,
5512 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513{
5514 /* BB assumes one setup word */
5515 TRANSACTION2_QPI_REQ *pSMB = NULL;
5516 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5517 int rc = 0;
5518 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005519 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005520 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005521 struct fea *temp_fea;
5522 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005523 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005524 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525
Joe Perchesb6b38f72010-04-21 03:50:45 +00005526 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527QAllEAsRetry:
5528 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5529 (void **) &pSMBr);
5530 if (rc)
5531 return rc;
5532
5533 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005534 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005535 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005536 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005537 list_len++; /* trailing null */
5538 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005540 list_len = strnlen(searchName, PATH_MAX);
5541 list_len++; /* trailing null */
5542 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 }
5544
Jeff Layton6e462b92010-02-10 16:18:26 -05005545 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 pSMB->TotalDataCount = 0;
5547 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005548 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005549 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 pSMB->MaxSetupCount = 0;
5551 pSMB->Reserved = 0;
5552 pSMB->Flags = 0;
5553 pSMB->Timeout = 0;
5554 pSMB->Reserved2 = 0;
5555 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005556 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 pSMB->DataCount = 0;
5558 pSMB->DataOffset = 0;
5559 pSMB->SetupCount = 1;
5560 pSMB->Reserved3 = 0;
5561 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5562 byte_count = params + 1 /* pad */ ;
5563 pSMB->TotalParameterCount = cpu_to_le16(params);
5564 pSMB->ParameterCount = pSMB->TotalParameterCount;
5565 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5566 pSMB->Reserved4 = 0;
5567 pSMB->hdr.smb_buf_length += byte_count;
5568 pSMB->ByteCount = cpu_to_le16(byte_count);
5569
5570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5572 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005573 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005574 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005576
5577
5578 /* BB also check enough total bytes returned */
5579 /* BB we need to improve the validity checking
5580 of these trans2 responses */
5581
5582 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5583 if (rc || (pSMBr->ByteCount < 4)) {
5584 rc = -EIO; /* bad smb */
5585 goto QAllEAsOut;
5586 }
5587
5588 /* check that length of list is not more than bcc */
5589 /* check that each entry does not go beyond length
5590 of list */
5591 /* check that each element of each entry does not
5592 go beyond end of list */
5593 /* validate_trans2_offsets() */
5594 /* BB check if start of smb + data_offset > &bcc+ bcc */
5595
5596 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5597 ea_response_data = (struct fealist *)
5598 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5599
Jeff Layton6e462b92010-02-10 16:18:26 -05005600 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005601 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005602 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005603 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005604 goto QAllEAsOut;
5605 }
5606
Jeff Layton0cd126b2010-02-10 16:18:26 -05005607 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005608 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005609 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005610 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005611 rc = -EIO;
5612 goto QAllEAsOut;
5613 }
5614
Jeff Laytonf0d38682010-02-10 16:18:26 -05005615 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005616 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005617 temp_fea = ea_response_data->list;
5618 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005619 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005620 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005621 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005622
Jeff Layton6e462b92010-02-10 16:18:26 -05005623 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005624 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005625 /* make sure we can read name_len and value_len */
5626 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005627 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005628 rc = -EIO;
5629 goto QAllEAsOut;
5630 }
5631
5632 name_len = temp_fea->name_len;
5633 value_len = le16_to_cpu(temp_fea->value_len);
5634 list_len -= name_len + 1 + value_len;
5635 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005636 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005637 rc = -EIO;
5638 goto QAllEAsOut;
5639 }
5640
Jeff Layton31c05192010-02-10 16:18:26 -05005641 if (ea_name) {
5642 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5643 temp_ptr += name_len + 1;
5644 rc = value_len;
5645 if (buf_size == 0)
5646 goto QAllEAsOut;
5647 if ((size_t)value_len > buf_size) {
5648 rc = -ERANGE;
5649 goto QAllEAsOut;
5650 }
5651 memcpy(EAData, temp_ptr, value_len);
5652 goto QAllEAsOut;
5653 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005654 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005655 /* account for prefix user. and trailing null */
5656 rc += (5 + 1 + name_len);
5657 if (rc < (int) buf_size) {
5658 memcpy(EAData, "user.", 5);
5659 EAData += 5;
5660 memcpy(EAData, temp_ptr, name_len);
5661 EAData += name_len;
5662 /* null terminate name */
5663 *EAData = 0;
5664 ++EAData;
5665 } else if (buf_size == 0) {
5666 /* skip copy - calc size only */
5667 } else {
5668 /* stop before overrun buffer */
5669 rc = -ERANGE;
5670 break;
5671 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005672 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005673 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005674 temp_fea = (struct fea *)temp_ptr;
5675 }
5676
Jeff Layton31c05192010-02-10 16:18:26 -05005677 /* didn't find the named attribute */
5678 if (ea_name)
5679 rc = -ENODATA;
5680
Jeff Laytonf0d38682010-02-10 16:18:26 -05005681QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005682 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 if (rc == -EAGAIN)
5684 goto QAllEAsRetry;
5685
5686 return (ssize_t)rc;
5687}
5688
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689int
5690CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005691 const char *ea_name, const void *ea_value,
5692 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5693 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694{
5695 struct smb_com_transaction2_spi_req *pSMB = NULL;
5696 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5697 struct fealist *parm_data;
5698 int name_len;
5699 int rc = 0;
5700 int bytes_returned = 0;
5701 __u16 params, param_offset, byte_count, offset, count;
5702
Joe Perchesb6b38f72010-04-21 03:50:45 +00005703 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704SetEARetry:
5705 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5706 (void **) &pSMBr);
5707 if (rc)
5708 return rc;
5709
5710 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5711 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005712 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005713 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 name_len++; /* trailing null */
5715 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005716 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717 name_len = strnlen(fileName, PATH_MAX);
5718 name_len++; /* trailing null */
5719 strncpy(pSMB->FileName, fileName, name_len);
5720 }
5721
5722 params = 6 + name_len;
5723
5724 /* done calculating parms using name_len of file name,
5725 now use name_len to calculate length of ea name
5726 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005727 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728 name_len = 0;
5729 else
Steve French50c2f752007-07-13 00:33:32 +00005730 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005732 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005734 /* BB find max SMB PDU from sess */
5735 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736 pSMB->MaxSetupCount = 0;
5737 pSMB->Reserved = 0;
5738 pSMB->Flags = 0;
5739 pSMB->Timeout = 0;
5740 pSMB->Reserved2 = 0;
5741 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005742 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 offset = param_offset + params;
5744 pSMB->InformationLevel =
5745 cpu_to_le16(SMB_SET_FILE_EA);
5746
5747 parm_data =
5748 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5749 offset);
5750 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5751 pSMB->DataOffset = cpu_to_le16(offset);
5752 pSMB->SetupCount = 1;
5753 pSMB->Reserved3 = 0;
5754 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5755 byte_count = 3 /* pad */ + params + count;
5756 pSMB->DataCount = cpu_to_le16(count);
5757 parm_data->list_len = cpu_to_le32(count);
5758 parm_data->list[0].EA_flags = 0;
5759 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005760 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005762 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005763 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 parm_data->list[0].name[name_len] = 0;
5765 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5766 /* caller ensures that ea_value_len is less than 64K but
5767 we need to ensure that it fits within the smb */
5768
Steve French50c2f752007-07-13 00:33:32 +00005769 /*BB add length check to see if it would fit in
5770 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005771 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5772 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005773 memcpy(parm_data->list[0].name+name_len+1,
5774 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775
5776 pSMB->TotalDataCount = pSMB->DataCount;
5777 pSMB->ParameterCount = cpu_to_le16(params);
5778 pSMB->TotalParameterCount = pSMB->ParameterCount;
5779 pSMB->Reserved4 = 0;
5780 pSMB->hdr.smb_buf_length += byte_count;
5781 pSMB->ByteCount = cpu_to_le16(byte_count);
5782 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5783 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005784 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005785 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786
5787 cifs_buf_release(pSMB);
5788
5789 if (rc == -EAGAIN)
5790 goto SetEARetry;
5791
5792 return rc;
5793}
5794
5795#endif