]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/cifssmb.c
[CIFS] Fix ntlmv2 auth with ntlmssp
[net-next-2.6.git] / fs / cifs / cifssmb.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/cifssmb.c
3 *
f19159dc 4 * Copyright (C) International Business Machines Corp., 2002,2010
1da177e4
LT
5 * 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 */
2dd29d31
SF
27 /* 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 */
1da177e4
LT
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
5a0e3ad6 33#include <linux/slab.h>
1da177e4
LT
34#include <linux/posix_acl_xattr.h>
35#include <asm/uaccess.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
d0d66c44 38#include "cifsacl.h"
1da177e4
LT
39#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[] = {
3979877e
SF
48#ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
9ac00b7d 50 {LANMAN2_PROT, "\2LANMAN2.1"},
3979877e 51#endif /* weak password hashing for legacy clients */
50c2f753 52 {CIFS_PROT, "\2NT LM 0.12"},
3979877e 53 {POSIX_PROT, "\2POSIX 2"},
1da177e4
LT
54 {BAD_PROT, "\2"}
55};
56#else
57static struct {
58 int index;
59 char *name;
60} protocols[] = {
3979877e
SF
61#ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
18f75ca0 63 {LANMAN2_PROT, "\2LANMAN2.1"},
3979877e 64#endif /* weak password hashing for legacy clients */
790fe579 65 {CIFS_PROT, "\2NT LM 0.12"},
1da177e4
LT
66 {BAD_PROT, "\2"}
67};
68#endif
69
3979877e
SF
70/* define the number of elements in the cifs dialect array */
71#ifdef CONFIG_CIFS_POSIX
72#ifdef CONFIG_CIFS_WEAK_PW_HASH
9ac00b7d 73#define CIFS_NUM_PROT 4
3979877e
SF
74#else
75#define CIFS_NUM_PROT 2
76#endif /* CIFS_WEAK_PW_HASH */
77#else /* not posix */
78#ifdef CONFIG_CIFS_WEAK_PW_HASH
9ac00b7d 79#define CIFS_NUM_PROT 3
3979877e
SF
80#else
81#define CIFS_NUM_PROT 1
82#endif /* CONFIG_CIFS_WEAK_PW_HASH */
83#endif /* CIFS_POSIX */
84
1da177e4
LT
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
790fe579 87static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
1da177e4
LT
88{
89 struct cifsFileInfo *open_file = NULL;
790fe579
SF
90 struct list_head *tmp;
91 struct list_head *tmp1;
1da177e4
LT
92
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
790fe579 96 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
ad8b15f0 97 open_file->invalidHandle = true;
3bc303c2 98 open_file->oplock_break_cancelled = true;
1da177e4
LT
99 }
100 write_unlock(&GlobalSMBSeslock);
09d1db5c
SF
101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
1da177e4
LT
103}
104
9162ab20
JL
105/* 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) {
b6b38f70
JP
133 cFYI(1, "can not send cmd %d while umounting",
134 smb_command);
9162ab20
JL
135 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) {
b6b38f70 160 cFYI(1, "gave up waiting on reconnect in smb_init");
9162ab20
JL
161 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 */
d7b619cf 174 mutex_lock(&ses->session_mutex);
198b5682
JL
175 rc = cifs_negotiate_protocol(0, ses);
176 if (rc == 0 && ses->need_reconnect)
9162ab20
JL
177 rc = cifs_setup_session(0, ses, nls_codepage);
178
179 /* do we need to reconnect tcon? */
180 if (rc || !tcon->need_reconnect) {
d7b619cf 181 mutex_unlock(&ses->session_mutex);
9162ab20
JL
182 goto out;
183 }
184
185 mark_open_files_invalid(tcon);
186 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
d7b619cf 187 mutex_unlock(&ses->session_mutex);
b6b38f70 188 cFYI(1, "reconnect tcon rc = %d", rc);
9162ab20
JL
189
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
ad7a2926
SF
228/* 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 */
1da177e4
LT
231static int
232small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
ad7a2926 233 void **request_buf)
1da177e4
LT
234{
235 int rc = 0;
236
9162ab20 237 rc = cifs_reconnect_tcon(tcon, smb_command);
790fe579 238 if (rc)
1da177e4
LT
239 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
63135e08 247 header_assemble((struct smb_hdr *) *request_buf, smb_command,
c18c842b 248 tcon, wct);
1da177e4 249
790fe579
SF
250 if (tcon != NULL)
251 cifs_stats_inc(&tcon->num_smbs_sent);
a4544347 252
1da177e4 253 return rc;
5815449d
SF
254}
255
12b3b8ff 256int
50c2f753 257small_smb_init_no_tc(const int smb_command, const int wct,
5815449d 258 struct cifsSesInfo *ses, void **request_buf)
12b3b8ff
SF
259{
260 int rc;
50c2f753 261 struct smb_hdr *buffer;
12b3b8ff 262
5815449d 263 rc = small_smb_init(smb_command, wct, NULL, request_buf);
790fe579 264 if (rc)
12b3b8ff
SF
265 return rc;
266
04fdabe1 267 buffer = (struct smb_hdr *)*request_buf;
12b3b8ff
SF
268 buffer->Mid = GetNextMid(ses->server);
269 if (ses->capabilities & CAP_UNICODE)
270 buffer->Flags2 |= SMBFLG2_UNICODE;
04fdabe1 271 if (ses->capabilities & CAP_STATUS32)
12b3b8ff
SF
272 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
273
274 /* uid, tid can stay at zero as set in header assemble */
275
50c2f753 276 /* BB add support for turning on the signing when
12b3b8ff
SF
277 this function is used after 1st of session setup requests */
278
279 return rc;
280}
1da177e4
LT
281
282/* If the return code is zero, this function must fill in request_buf pointer */
283static int
284smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
285 void **request_buf /* returned */ ,
286 void **response_buf /* returned */ )
287{
288 int rc = 0;
289
9162ab20 290 rc = cifs_reconnect_tcon(tcon, smb_command);
790fe579 291 if (rc)
1da177e4
LT
292 return rc;
293
294 *request_buf = cifs_buf_get();
295 if (*request_buf == NULL) {
296 /* BB should we add a retry in here if not a writepage? */
297 return -ENOMEM;
298 }
299 /* Although the original thought was we needed the response buf for */
300 /* potential retries of smb operations it turns out we can determine */
301 /* from the mid flags when the request buffer can be resent without */
302 /* having to use a second distinct buffer for the response */
790fe579 303 if (response_buf)
50c2f753 304 *response_buf = *request_buf;
1da177e4
LT
305
306 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
ad7a2926 307 wct);
1da177e4 308
790fe579
SF
309 if (tcon != NULL)
310 cifs_stats_inc(&tcon->num_smbs_sent);
a4544347 311
1da177e4
LT
312 return rc;
313}
314
50c2f753 315static int validate_t2(struct smb_t2_rsp *pSMB)
1da177e4
LT
316{
317 int rc = -EINVAL;
318 int total_size;
50c2f753 319 char *pBCC;
1da177e4
LT
320
321 /* check for plausible wct, bcc and t2 data and parm sizes */
322 /* check for parm and data offset going beyond end of smb */
790fe579
SF
323 if (pSMB->hdr.WordCount >= 10) {
324 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
1da177e4
LT
325 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
326 /* check that bcc is at least as big as parms + data */
327 /* check that bcc is less than negotiated smb buffer */
328 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
790fe579 329 if (total_size < 512) {
c18c842b 330 total_size +=
63135e08 331 le16_to_cpu(pSMB->t2_rsp.DataCount);
1da177e4 332 /* BCC le converted in SendReceive */
50c2f753 333 pBCC = (pSMB->hdr.WordCount * 2) +
09d1db5c 334 sizeof(struct smb_hdr) +
1da177e4 335 (char *)pSMB;
790fe579 336 if ((total_size <= (*(u16 *)pBCC)) &&
50c2f753 337 (total_size <
1da177e4
LT
338 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
339 return 0;
340 }
1da177e4
LT
341 }
342 }
343 }
50c2f753 344 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
1da177e4
LT
345 sizeof(struct smb_t2_rsp) + 16);
346 return rc;
347}
348int
349CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
350{
351 NEGOTIATE_REQ *pSMB;
352 NEGOTIATE_RSP *pSMBr;
353 int rc = 0;
354 int bytes_returned;
3979877e 355 int i;
50c2f753 356 struct TCP_Server_Info *server;
1da177e4 357 u16 count;
750d1151 358 unsigned int secFlags;
1da177e4 359
790fe579 360 if (ses->server)
1da177e4
LT
361 server = ses->server;
362 else {
363 rc = -EIO;
364 return rc;
365 }
366 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
367 (void **) &pSMB, (void **) &pSMBr);
368 if (rc)
369 return rc;
750d1151
SF
370
371 /* if any of auth flags (ie not sign or seal) are overriden use them */
790fe579 372 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
762e5ab7 373 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
750d1151 374 else /* if override flags set only sign/seal OR them with global auth */
04912d6a 375 secFlags = global_secflags | ses->overrideSecFlg;
750d1151 376
b6b38f70 377 cFYI(1, "secFlags 0x%x", secFlags);
f40c5628 378
1982c344 379 pSMB->hdr.Mid = GetNextMid(server);
100c1ddc 380 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
a013689d 381
100c1ddc 382 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
254e55ed 383 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
a013689d 384 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
b6b38f70 385 cFYI(1, "Kerberos only mechanism, enable extended security");
a013689d
SF
386 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
387 }
ac683924
SF
388#ifdef CONFIG_CIFS_EXPERIMENTAL
389 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
390 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
391 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
b6b38f70 392 cFYI(1, "NTLMSSP only mechanism, enable extended security");
ac683924
SF
393 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
394 }
395#endif
50c2f753 396
3979877e 397 count = 0;
50c2f753 398 for (i = 0; i < CIFS_NUM_PROT; i++) {
3979877e
SF
399 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
400 count += strlen(protocols[i].name) + 1;
401 /* null at end of source and target buffers anyway */
402 }
1da177e4
LT
403 pSMB->hdr.smb_buf_length += count;
404 pSMB->ByteCount = cpu_to_le16(count);
405
406 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
50c2f753 408 if (rc != 0)
254e55ed
SF
409 goto neg_err_exit;
410
9bf67e51
JL
411 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
412 cFYI(1, "Dialect: %d", server->dialect);
254e55ed 413 /* Check wct = 1 error case */
9bf67e51 414 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
254e55ed 415 /* core returns wct = 1, but we do not ask for core - otherwise
50c2f753 416 small wct just comes when dialect index is -1 indicating we
254e55ed
SF
417 could not negotiate a common dialect */
418 rc = -EOPNOTSUPP;
419 goto neg_err_exit;
50c2f753 420#ifdef CONFIG_CIFS_WEAK_PW_HASH
790fe579 421 } else if ((pSMBr->hdr.WordCount == 13)
9bf67e51
JL
422 && ((server->dialect == LANMAN_PROT)
423 || (server->dialect == LANMAN2_PROT))) {
b815f1e5 424 __s16 tmp;
50c2f753 425 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
254e55ed 426
790fe579 427 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
750d1151 428 (secFlags & CIFSSEC_MAY_PLNTXT))
254e55ed
SF
429 server->secType = LANMAN;
430 else {
b6b38f70
JP
431 cERROR(1, "mount failed weak security disabled"
432 " in /proc/fs/cifs/SecurityFlags");
3979877e
SF
433 rc = -EOPNOTSUPP;
434 goto neg_err_exit;
50c2f753 435 }
254e55ed
SF
436 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
437 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
438 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
3979877e 439 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
eca6acf9 440 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
254e55ed
SF
441 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
442 /* even though we do not use raw we might as well set this
443 accurately, in case we ever find a need for it */
790fe579 444 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
eca6acf9 445 server->max_rw = 0xFF00;
254e55ed
SF
446 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
447 } else {
eca6acf9 448 server->max_rw = 0;/* do not need to use raw anyway */
254e55ed
SF
449 server->capabilities = CAP_MPX_MODE;
450 }
b815f1e5 451 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
1a70d652 452 if (tmp == -1) {
25ee4a98
SF
453 /* OS/2 often does not set timezone therefore
454 * we must use server time to calc time zone.
b815f1e5
SF
455 * Could deviate slightly from the right zone.
456 * Smallest defined timezone difference is 15 minutes
457 * (i.e. Nepal). Rounding up/down is done to match
458 * this requirement.
25ee4a98 459 */
b815f1e5 460 int val, seconds, remain, result;
25ee4a98
SF
461 struct timespec ts, utc;
462 utc = CURRENT_TIME;
c4a2c08d
JL
463 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
464 rsp->SrvTime.Time, 0);
b6b38f70 465 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
50c2f753 466 (int)ts.tv_sec, (int)utc.tv_sec,
b6b38f70 467 (int)(utc.tv_sec - ts.tv_sec));
b815f1e5 468 val = (int)(utc.tv_sec - ts.tv_sec);
8594c15a 469 seconds = abs(val);
947a5067 470 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
b815f1e5 471 remain = seconds % MIN_TZ_ADJ;
790fe579 472 if (remain >= (MIN_TZ_ADJ / 2))
b815f1e5 473 result += MIN_TZ_ADJ;
790fe579 474 if (val < 0)
ad7a2926 475 result = -result;
b815f1e5 476 server->timeAdj = result;
25ee4a98 477 } else {
b815f1e5
SF
478 server->timeAdj = (int)tmp;
479 server->timeAdj *= 60; /* also in seconds */
25ee4a98 480 }
b6b38f70 481 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
25ee4a98 482
3979877e 483
254e55ed 484 /* BB get server time for time conversions and add
50c2f753 485 code to use it and timezone since this is not UTC */
3979877e 486
50c2f753 487 if (rsp->EncryptionKeyLength ==
25ee4a98 488 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
254e55ed
SF
489 memcpy(server->cryptKey, rsp->EncryptionKey,
490 CIFS_CRYPTO_KEY_SIZE);
491 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
492 rc = -EIO; /* need cryptkey unless plain text */
493 goto neg_err_exit;
494 }
3979877e 495
f19159dc 496 cFYI(1, "LANMAN negotiated");
254e55ed
SF
497 /* we will not end up setting signing flags - as no signing
498 was in LANMAN and server did not return the flags on */
499 goto signing_check;
7c7b25bc 500#else /* weak security disabled */
790fe579 501 } else if (pSMBr->hdr.WordCount == 13) {
f19159dc
SF
502 cERROR(1, "mount failed, cifs module not built "
503 "with CIFS_WEAK_PW_HASH support");
8212cf75 504 rc = -EOPNOTSUPP;
7c7b25bc 505#endif /* WEAK_PW_HASH */
254e55ed 506 goto neg_err_exit;
790fe579 507 } else if (pSMBr->hdr.WordCount != 17) {
254e55ed
SF
508 /* unknown wct */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
511 }
512 /* else wct == 17 NTLM */
513 server->secMode = pSMBr->SecurityMode;
790fe579 514 if ((server->secMode & SECMODE_USER) == 0)
b6b38f70 515 cFYI(1, "share mode security");
bdc4bf6e 516
790fe579 517 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
bdc4bf6e 518#ifdef CONFIG_CIFS_WEAK_PW_HASH
750d1151 519 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
bdc4bf6e 520#endif /* CIFS_WEAK_PW_HASH */
b6b38f70
JP
521 cERROR(1, "Server requests plain text password"
522 " but client support disabled");
9312f675 523
790fe579 524 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
254e55ed 525 server->secType = NTLMv2;
790fe579 526 else if (secFlags & CIFSSEC_MAY_NTLM)
254e55ed 527 server->secType = NTLM;
790fe579 528 else if (secFlags & CIFSSEC_MAY_NTLMV2)
f40c5628 529 server->secType = NTLMv2;
a013689d
SF
530 else if (secFlags & CIFSSEC_MAY_KRB5)
531 server->secType = Kerberos;
ac683924 532 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
f46c7234 533 server->secType = RawNTLMSSP;
a013689d
SF
534 else if (secFlags & CIFSSEC_MAY_LANMAN)
535 server->secType = LANMAN;
536/* #ifdef CONFIG_CIFS_EXPERIMENTAL
537 else if (secFlags & CIFSSEC_MAY_PLNTXT)
538 server->secType = ??
539#endif */
540 else {
541 rc = -EOPNOTSUPP;
b6b38f70 542 cERROR(1, "Invalid security type");
a013689d
SF
543 goto neg_err_exit;
544 }
545 /* else ... any others ...? */
254e55ed
SF
546
547 /* one byte, so no need to convert this or EncryptionKeyLen from
548 little endian */
549 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
550 /* probably no need to store and check maxvcs */
551 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
1da177e4 552 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
eca6acf9 553 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
b6b38f70 554 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
254e55ed
SF
555 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
556 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
b815f1e5
SF
557 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
558 server->timeAdj *= 60;
254e55ed
SF
559 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
560 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
561 CIFS_CRYPTO_KEY_SIZE);
562 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
563 && (pSMBr->EncryptionKeyLength == 0)) {
564 /* decode security blob */
565 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
566 rc = -EIO; /* no crypt key only if plain text pwd */
567 goto neg_err_exit;
568 }
1da177e4 569
254e55ed
SF
570 /* BB might be helpful to save off the domain of server here */
571
50c2f753 572 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
254e55ed
SF
573 (server->capabilities & CAP_EXTENDED_SECURITY)) {
574 count = pSMBr->ByteCount;
e187e44e 575 if (count < 16) {
254e55ed 576 rc = -EIO;
e187e44e
JL
577 goto neg_err_exit;
578 }
e7ddee90
JL
579 read_lock(&cifs_tcp_ses_lock);
580 if (server->srv_count > 1) {
581 read_unlock(&cifs_tcp_ses_lock);
e187e44e
JL
582 if (memcmp(server->server_GUID,
583 pSMBr->u.extended_response.
584 GUID, 16) != 0) {
b6b38f70 585 cFYI(1, "server UID changed");
254e55ed 586 memcpy(server->server_GUID,
e187e44e
JL
587 pSMBr->u.extended_response.GUID,
588 16);
589 }
e7ddee90
JL
590 } else {
591 read_unlock(&cifs_tcp_ses_lock);
e187e44e
JL
592 memcpy(server->server_GUID,
593 pSMBr->u.extended_response.GUID, 16);
e7ddee90 594 }
e187e44e
JL
595
596 if (count == 16) {
597 server->secType = RawNTLMSSP;
254e55ed
SF
598 } else {
599 rc = decode_negTokenInit(pSMBr->u.extended_response.
26efa0ba
JL
600 SecurityBlob, count - 16,
601 server);
ef571cad 602 if (rc == 1)
e545937a 603 rc = 0;
ef571cad 604 else
254e55ed 605 rc = -EINVAL;
26efa0ba 606
9fbc5908
SF
607 if (server->secType == Kerberos) {
608 if (!server->sec_kerberos &&
609 !server->sec_mskerberos)
610 rc = -EOPNOTSUPP;
611 } else if (server->secType == RawNTLMSSP) {
612 if (!server->sec_ntlmssp)
613 rc = -EOPNOTSUPP;
614 } else
26efa0ba 615 rc = -EOPNOTSUPP;
1da177e4 616 }
254e55ed
SF
617 } else
618 server->capabilities &= ~CAP_EXTENDED_SECURITY;
619
6344a423 620#ifdef CONFIG_CIFS_WEAK_PW_HASH
254e55ed 621signing_check:
6344a423 622#endif
762e5ab7
SF
623 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
624 /* MUST_SIGN already includes the MAY_SIGN FLAG
625 so if this is zero it means that signing is disabled */
b6b38f70 626 cFYI(1, "Signing disabled");
abb63d6c 627 if (server->secMode & SECMODE_SIGN_REQUIRED) {
b6b38f70 628 cERROR(1, "Server requires "
7111d214 629 "packet signing to be enabled in "
b6b38f70 630 "/proc/fs/cifs/SecurityFlags.");
abb63d6c
SF
631 rc = -EOPNOTSUPP;
632 }
50c2f753 633 server->secMode &=
254e55ed 634 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
762e5ab7
SF
635 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
636 /* signing required */
b6b38f70 637 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
762e5ab7
SF
638 if ((server->secMode &
639 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
b6b38f70 640 cERROR(1, "signing required but server lacks support");
38c10a1d 641 rc = -EOPNOTSUPP;
762e5ab7
SF
642 } else
643 server->secMode |= SECMODE_SIGN_REQUIRED;
644 } else {
645 /* signing optional ie CIFSSEC_MAY_SIGN */
790fe579 646 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
50c2f753 647 server->secMode &=
254e55ed 648 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
1da177e4 649 }
50c2f753
SF
650
651neg_err_exit:
4a6d87f1 652 cifs_buf_release(pSMB);
254e55ed 653
b6b38f70 654 cFYI(1, "negprot rc %d", rc);
1da177e4
LT
655 return rc;
656}
657
658int
659CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
660{
661 struct smb_hdr *smb_buffer;
1da177e4 662 int rc = 0;
1da177e4 663
b6b38f70 664 cFYI(1, "In tree disconnect");
1da177e4 665
f1987b44
JL
666 /* BB: do we need to check this? These should never be NULL. */
667 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
668 return -EIO;
1da177e4 669
f1987b44
JL
670 /*
671 * No need to return error on this operation if tid invalidated and
672 * closed on server already e.g. due to tcp session crashing. Also,
673 * the tcon is no longer on the list, so no need to take lock before
674 * checking this.
675 */
268875b9 676 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
50c2f753 677 return 0;
1da177e4 678
50c2f753 679 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
09d1db5c 680 (void **)&smb_buffer);
f1987b44 681 if (rc)
1da177e4 682 return rc;
133672ef
SF
683
684 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
1da177e4 685 if (rc)
b6b38f70 686 cFYI(1, "Tree disconnect failed %d", rc);
1da177e4 687
50c2f753 688 /* No need to return error on this operation if tid invalidated and
f1987b44 689 closed on server already e.g. due to tcp session crashing */
1da177e4
LT
690 if (rc == -EAGAIN)
691 rc = 0;
692
693 return rc;
694}
695
696int
697CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
698{
1da177e4
LT
699 LOGOFF_ANDX_REQ *pSMB;
700 int rc = 0;
1da177e4 701
b6b38f70 702 cFYI(1, "In SMBLogoff for session disconnect");
3b795210 703
14fbf50d
JL
704 /*
705 * BB: do we need to check validity of ses and server? They should
706 * always be valid since we have an active reference. If not, that
707 * should probably be a BUG()
708 */
709 if (!ses || !ses->server)
3b795210
SF
710 return -EIO;
711
d7b619cf 712 mutex_lock(&ses->session_mutex);
3b795210
SF
713 if (ses->need_reconnect)
714 goto session_already_dead; /* no need to send SMBlogoff if uid
715 already closed due to reconnect */
1da177e4
LT
716 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
717 if (rc) {
d7b619cf 718 mutex_unlock(&ses->session_mutex);
1da177e4
LT
719 return rc;
720 }
721
3b795210 722 pSMB->hdr.Mid = GetNextMid(ses->server);
1982c344 723
3b795210 724 if (ses->server->secMode &
1da177e4
LT
725 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
726 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1da177e4
LT
727
728 pSMB->hdr.Uid = ses->Suid;
729
730 pSMB->AndXCommand = 0xFF;
133672ef 731 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
3b795210 732session_already_dead:
d7b619cf 733 mutex_unlock(&ses->session_mutex);
1da177e4
LT
734
735 /* if session dead then we do not need to do ulogoff,
50c2f753 736 since server closed smb session, no sense reporting
1da177e4
LT
737 error */
738 if (rc == -EAGAIN)
739 rc = 0;
740 return rc;
741}
742
2d785a50
SF
743int
744CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
745 __u16 type, const struct nls_table *nls_codepage, int remap)
746{
747 TRANSACTION2_SPI_REQ *pSMB = NULL;
748 TRANSACTION2_SPI_RSP *pSMBr = NULL;
749 struct unlink_psx_rq *pRqD;
750 int name_len;
751 int rc = 0;
752 int bytes_returned = 0;
753 __u16 params, param_offset, offset, byte_count;
754
b6b38f70 755 cFYI(1, "In POSIX delete");
2d785a50
SF
756PsxDelete:
757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
758 (void **) &pSMBr);
759 if (rc)
760 return rc;
761
762 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
763 name_len =
764 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
765 PATH_MAX, nls_codepage, remap);
766 name_len++; /* trailing null */
767 name_len *= 2;
768 } else { /* BB add path length overrun check */
769 name_len = strnlen(fileName, PATH_MAX);
770 name_len++; /* trailing null */
771 strncpy(pSMB->FileName, fileName, name_len);
772 }
773
774 params = 6 + name_len;
775 pSMB->MaxParameterCount = cpu_to_le16(2);
776 pSMB->MaxDataCount = 0; /* BB double check this with jra */
777 pSMB->MaxSetupCount = 0;
778 pSMB->Reserved = 0;
779 pSMB->Flags = 0;
780 pSMB->Timeout = 0;
781 pSMB->Reserved2 = 0;
782 param_offset = offsetof(struct smb_com_transaction2_spi_req,
783 InformationLevel) - 4;
784 offset = param_offset + params;
785
786 /* Setup pointer to Request Data (inode type) */
787 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
788 pRqD->type = cpu_to_le16(type);
789 pSMB->ParameterOffset = cpu_to_le16(param_offset);
790 pSMB->DataOffset = cpu_to_le16(offset);
791 pSMB->SetupCount = 1;
792 pSMB->Reserved3 = 0;
793 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
794 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
795
796 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
797 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
798 pSMB->ParameterCount = cpu_to_le16(params);
799 pSMB->TotalParameterCount = pSMB->ParameterCount;
800 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
801 pSMB->Reserved4 = 0;
802 pSMB->hdr.smb_buf_length += byte_count;
803 pSMB->ByteCount = cpu_to_le16(byte_count);
804 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
805 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 806 if (rc)
b6b38f70 807 cFYI(1, "Posix delete returned %d", rc);
2d785a50
SF
808 cifs_buf_release(pSMB);
809
810 cifs_stats_inc(&tcon->num_deletes);
811
812 if (rc == -EAGAIN)
813 goto PsxDelete;
814
815 return rc;
816}
817
1da177e4 818int
737b758c
SF
819CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
820 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
821{
822 DELETE_FILE_REQ *pSMB = NULL;
823 DELETE_FILE_RSP *pSMBr = NULL;
824 int rc = 0;
825 int bytes_returned;
826 int name_len;
827
828DelFileRetry:
829 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
830 (void **) &pSMBr);
831 if (rc)
832 return rc;
833
834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
835 name_len =
50c2f753 836 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
737b758c 837 PATH_MAX, nls_codepage, remap);
1da177e4
LT
838 name_len++; /* trailing null */
839 name_len *= 2;
09d1db5c 840 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
841 name_len = strnlen(fileName, PATH_MAX);
842 name_len++; /* trailing null */
843 strncpy(pSMB->fileName, fileName, name_len);
844 }
845 pSMB->SearchAttributes =
846 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
847 pSMB->BufferFormat = 0x04;
848 pSMB->hdr.smb_buf_length += name_len + 1;
849 pSMB->ByteCount = cpu_to_le16(name_len + 1);
850 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 852 cifs_stats_inc(&tcon->num_deletes);
ad7a2926 853 if (rc)
b6b38f70 854 cFYI(1, "Error in RMFile = %d", rc);
1da177e4
LT
855
856 cifs_buf_release(pSMB);
857 if (rc == -EAGAIN)
858 goto DelFileRetry;
859
860 return rc;
861}
862
863int
50c2f753 864CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
737b758c 865 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
866{
867 DELETE_DIRECTORY_REQ *pSMB = NULL;
868 DELETE_DIRECTORY_RSP *pSMBr = NULL;
869 int rc = 0;
870 int bytes_returned;
871 int name_len;
872
b6b38f70 873 cFYI(1, "In CIFSSMBRmDir");
1da177e4
LT
874RmDirRetry:
875 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
876 (void **) &pSMBr);
877 if (rc)
878 return rc;
879
880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
737b758c
SF
881 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
882 PATH_MAX, nls_codepage, remap);
1da177e4
LT
883 name_len++; /* trailing null */
884 name_len *= 2;
09d1db5c 885 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
886 name_len = strnlen(dirName, PATH_MAX);
887 name_len++; /* trailing null */
888 strncpy(pSMB->DirName, dirName, name_len);
889 }
890
891 pSMB->BufferFormat = 0x04;
892 pSMB->hdr.smb_buf_length += name_len + 1;
893 pSMB->ByteCount = cpu_to_le16(name_len + 1);
894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 896 cifs_stats_inc(&tcon->num_rmdirs);
ad7a2926 897 if (rc)
b6b38f70 898 cFYI(1, "Error in RMDir = %d", rc);
1da177e4
LT
899
900 cifs_buf_release(pSMB);
901 if (rc == -EAGAIN)
902 goto RmDirRetry;
903 return rc;
904}
905
906int
907CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
737b758c 908 const char *name, const struct nls_table *nls_codepage, int remap)
1da177e4
LT
909{
910 int rc = 0;
911 CREATE_DIRECTORY_REQ *pSMB = NULL;
912 CREATE_DIRECTORY_RSP *pSMBr = NULL;
913 int bytes_returned;
914 int name_len;
915
b6b38f70 916 cFYI(1, "In CIFSSMBMkDir");
1da177e4
LT
917MkDirRetry:
918 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
919 (void **) &pSMBr);
920 if (rc)
921 return rc;
922
923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
50c2f753 924 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
737b758c 925 PATH_MAX, nls_codepage, remap);
1da177e4
LT
926 name_len++; /* trailing null */
927 name_len *= 2;
09d1db5c 928 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
929 name_len = strnlen(name, PATH_MAX);
930 name_len++; /* trailing null */
931 strncpy(pSMB->DirName, name, name_len);
932 }
933
934 pSMB->BufferFormat = 0x04;
935 pSMB->hdr.smb_buf_length += name_len + 1;
936 pSMB->ByteCount = cpu_to_le16(name_len + 1);
937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 939 cifs_stats_inc(&tcon->num_mkdirs);
ad7a2926 940 if (rc)
b6b38f70 941 cFYI(1, "Error in Mkdir = %d", rc);
a5a2b489 942
1da177e4
LT
943 cifs_buf_release(pSMB);
944 if (rc == -EAGAIN)
945 goto MkDirRetry;
946 return rc;
947}
948
2dd29d31
SF
949int
950CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
ad7a2926 951 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
50c2f753 952 __u32 *pOplock, const char *name,
2dd29d31
SF
953 const struct nls_table *nls_codepage, int remap)
954{
955 TRANSACTION2_SPI_REQ *pSMB = NULL;
956 TRANSACTION2_SPI_RSP *pSMBr = NULL;
957 int name_len;
958 int rc = 0;
959 int bytes_returned = 0;
2dd29d31 960 __u16 params, param_offset, offset, byte_count, count;
ad7a2926
SF
961 OPEN_PSX_REQ *pdata;
962 OPEN_PSX_RSP *psx_rsp;
2dd29d31 963
b6b38f70 964 cFYI(1, "In POSIX Create");
2dd29d31
SF
965PsxCreat:
966 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
967 (void **) &pSMBr);
968 if (rc)
969 return rc;
970
971 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
972 name_len =
973 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
974 PATH_MAX, nls_codepage, remap);
975 name_len++; /* trailing null */
976 name_len *= 2;
977 } else { /* BB improve the check for buffer overruns BB */
978 name_len = strnlen(name, PATH_MAX);
979 name_len++; /* trailing null */
980 strncpy(pSMB->FileName, name, name_len);
981 }
982
983 params = 6 + name_len;
984 count = sizeof(OPEN_PSX_REQ);
985 pSMB->MaxParameterCount = cpu_to_le16(2);
986 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
987 pSMB->MaxSetupCount = 0;
988 pSMB->Reserved = 0;
989 pSMB->Flags = 0;
990 pSMB->Timeout = 0;
991 pSMB->Reserved2 = 0;
992 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 993 InformationLevel) - 4;
2dd29d31 994 offset = param_offset + params;
2dd29d31 995 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
8f2376ad 996 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2dd29d31 997 pdata->Permissions = cpu_to_le64(mode);
50c2f753 998 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
2dd29d31
SF
999 pdata->OpenFlags = cpu_to_le32(*pOplock);
1000 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1001 pSMB->DataOffset = cpu_to_le16(offset);
1002 pSMB->SetupCount = 1;
1003 pSMB->Reserved3 = 0;
1004 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1005 byte_count = 3 /* pad */ + params + count;
1006
1007 pSMB->DataCount = cpu_to_le16(count);
1008 pSMB->ParameterCount = cpu_to_le16(params);
1009 pSMB->TotalDataCount = pSMB->DataCount;
1010 pSMB->TotalParameterCount = pSMB->ParameterCount;
1011 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1012 pSMB->Reserved4 = 0;
50c2f753 1013 pSMB->hdr.smb_buf_length += byte_count;
2dd29d31
SF
1014 pSMB->ByteCount = cpu_to_le16(byte_count);
1015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1017 if (rc) {
b6b38f70 1018 cFYI(1, "Posix create returned %d", rc);
2dd29d31
SF
1019 goto psx_create_err;
1020 }
1021
b6b38f70 1022 cFYI(1, "copying inode info");
2dd29d31
SF
1023 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1024
1025 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1026 rc = -EIO; /* bad smb */
1027 goto psx_create_err;
1028 }
1029
1030 /* copy return information to pRetData */
50c2f753 1031 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
2dd29d31 1032 + le16_to_cpu(pSMBr->t2.DataOffset));
50c2f753 1033
2dd29d31 1034 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
790fe579 1035 if (netfid)
2dd29d31
SF
1036 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1037 /* Let caller know file was created so we can set the mode. */
1038 /* Do we care about the CreateAction in any other cases? */
790fe579 1039 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
2dd29d31
SF
1040 *pOplock |= CIFS_CREATE_ACTION;
1041 /* check to make sure response data is there */
8f2376ad
CG
1042 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1043 pRetData->Type = cpu_to_le32(-1); /* unknown */
b6b38f70 1044 cFYI(DBG2, "unknown type");
cbac3cba 1045 } else {
790fe579 1046 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
2dd29d31 1047 + sizeof(FILE_UNIX_BASIC_INFO)) {
b6b38f70 1048 cERROR(1, "Open response data too small");
8f2376ad 1049 pRetData->Type = cpu_to_le32(-1);
2dd29d31
SF
1050 goto psx_create_err;
1051 }
50c2f753 1052 memcpy((char *) pRetData,
cbac3cba 1053 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
26f57364 1054 sizeof(FILE_UNIX_BASIC_INFO));
2dd29d31 1055 }
2dd29d31
SF
1056
1057psx_create_err:
1058 cifs_buf_release(pSMB);
1059
65bc98b0
SF
1060 if (posix_flags & SMB_O_DIRECTORY)
1061 cifs_stats_inc(&tcon->num_posixmkdirs);
1062 else
1063 cifs_stats_inc(&tcon->num_posixopens);
2dd29d31
SF
1064
1065 if (rc == -EAGAIN)
1066 goto PsxCreat;
1067
50c2f753 1068 return rc;
2dd29d31
SF
1069}
1070
a9d02ad4
SF
1071static __u16 convert_disposition(int disposition)
1072{
1073 __u16 ofun = 0;
1074
1075 switch (disposition) {
1076 case FILE_SUPERSEDE:
1077 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1078 break;
1079 case FILE_OPEN:
1080 ofun = SMBOPEN_OAPPEND;
1081 break;
1082 case FILE_CREATE:
1083 ofun = SMBOPEN_OCREATE;
1084 break;
1085 case FILE_OPEN_IF:
1086 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1087 break;
1088 case FILE_OVERWRITE:
1089 ofun = SMBOPEN_OTRUNC;
1090 break;
1091 case FILE_OVERWRITE_IF:
1092 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1093 break;
1094 default:
b6b38f70 1095 cFYI(1, "unknown disposition %d", disposition);
a9d02ad4
SF
1096 ofun = SMBOPEN_OAPPEND; /* regular open */
1097 }
1098 return ofun;
1099}
1100
35fc37d5
JL
1101static int
1102access_flags_to_smbopen_mode(const int access_flags)
1103{
1104 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1105
1106 if (masked_flags == GENERIC_READ)
1107 return SMBOPEN_READ;
1108 else if (masked_flags == GENERIC_WRITE)
1109 return SMBOPEN_WRITE;
1110
1111 /* just go for read/write */
1112 return SMBOPEN_READWRITE;
1113}
1114
a9d02ad4
SF
1115int
1116SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1117 const char *fileName, const int openDisposition,
ad7a2926
SF
1118 const int access_flags, const int create_options, __u16 *netfid,
1119 int *pOplock, FILE_ALL_INFO *pfile_info,
a9d02ad4
SF
1120 const struct nls_table *nls_codepage, int remap)
1121{
1122 int rc = -EACCES;
1123 OPENX_REQ *pSMB = NULL;
1124 OPENX_RSP *pSMBr = NULL;
1125 int bytes_returned;
1126 int name_len;
1127 __u16 count;
1128
1129OldOpenRetry:
1130 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1131 (void **) &pSMBr);
1132 if (rc)
1133 return rc;
1134
1135 pSMB->AndXCommand = 0xFF; /* none */
1136
1137 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1138 count = 1; /* account for one byte pad to word boundary */
1139 name_len =
1140 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1141 fileName, PATH_MAX, nls_codepage, remap);
1142 name_len++; /* trailing null */
1143 name_len *= 2;
1144 } else { /* BB improve check for buffer overruns BB */
1145 count = 0; /* no pad */
1146 name_len = strnlen(fileName, PATH_MAX);
1147 name_len++; /* trailing null */
1148 strncpy(pSMB->fileName, fileName, name_len);
1149 }
1150 if (*pOplock & REQ_OPLOCK)
1151 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
26f57364 1152 else if (*pOplock & REQ_BATCHOPLOCK)
a9d02ad4 1153 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
26f57364 1154
a9d02ad4 1155 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
35fc37d5 1156 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
a9d02ad4
SF
1157 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1158 /* set file as system file if special file such
1159 as fifo and server expecting SFU style and
1160 no Unix extensions */
1161
790fe579
SF
1162 if (create_options & CREATE_OPTION_SPECIAL)
1163 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
ad7a2926
SF
1164 else /* BB FIXME BB */
1165 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
a9d02ad4 1166
67750fb9
JL
1167 if (create_options & CREATE_OPTION_READONLY)
1168 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
a9d02ad4
SF
1169
1170 /* BB FIXME BB */
50c2f753
SF
1171/* pSMB->CreateOptions = cpu_to_le32(create_options &
1172 CREATE_OPTIONS_MASK); */
a9d02ad4 1173 /* BB FIXME END BB */
3e87d803
SF
1174
1175 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
70ca734a 1176 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
a9d02ad4
SF
1177 count += name_len;
1178 pSMB->hdr.smb_buf_length += count;
1179
1180 pSMB->ByteCount = cpu_to_le16(count);
1181 /* long_op set to 1 to allow for oplock break timeouts */
1182 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef 1183 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
a9d02ad4
SF
1184 cifs_stats_inc(&tcon->num_opens);
1185 if (rc) {
b6b38f70 1186 cFYI(1, "Error in Open = %d", rc);
a9d02ad4
SF
1187 } else {
1188 /* BB verify if wct == 15 */
1189
582d21e5 1190/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
a9d02ad4
SF
1191
1192 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1193 /* Let caller know file was created so we can set the mode. */
1194 /* Do we care about the CreateAction in any other cases? */
1195 /* BB FIXME BB */
790fe579 1196/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
a9d02ad4
SF
1197 *pOplock |= CIFS_CREATE_ACTION; */
1198 /* BB FIXME END */
1199
790fe579 1200 if (pfile_info) {
a9d02ad4
SF
1201 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1202 pfile_info->LastAccessTime = 0; /* BB fixme */
1203 pfile_info->LastWriteTime = 0; /* BB fixme */
1204 pfile_info->ChangeTime = 0; /* BB fixme */
70ca734a 1205 pfile_info->Attributes =
50c2f753 1206 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
a9d02ad4 1207 /* the file_info buf is endian converted by caller */
70ca734a
SF
1208 pfile_info->AllocationSize =
1209 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1210 pfile_info->EndOfFile = pfile_info->AllocationSize;
a9d02ad4 1211 pfile_info->NumberOfLinks = cpu_to_le32(1);
9a8165fc 1212 pfile_info->DeletePending = 0;
a9d02ad4
SF
1213 }
1214 }
1215
1216 cifs_buf_release(pSMB);
1217 if (rc == -EAGAIN)
1218 goto OldOpenRetry;
1219 return rc;
1220}
1221
1da177e4
LT
1222int
1223CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1224 const char *fileName, const int openDisposition,
ad7a2926
SF
1225 const int access_flags, const int create_options, __u16 *netfid,
1226 int *pOplock, FILE_ALL_INFO *pfile_info,
737b758c 1227 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1228{
1229 int rc = -EACCES;
1230 OPEN_REQ *pSMB = NULL;
1231 OPEN_RSP *pSMBr = NULL;
1232 int bytes_returned;
1233 int name_len;
1234 __u16 count;
1235
1236openRetry:
1237 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1238 (void **) &pSMBr);
1239 if (rc)
1240 return rc;
1241
1242 pSMB->AndXCommand = 0xFF; /* none */
1243
1244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1245 count = 1; /* account for one byte pad to word boundary */
1246 name_len =
b1a45695 1247 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
737b758c 1248 fileName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1249 name_len++; /* trailing null */
1250 name_len *= 2;
1251 pSMB->NameLength = cpu_to_le16(name_len);
09d1db5c 1252 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
1253 count = 0; /* no pad */
1254 name_len = strnlen(fileName, PATH_MAX);
1255 name_len++; /* trailing null */
1256 pSMB->NameLength = cpu_to_le16(name_len);
1257 strncpy(pSMB->fileName, fileName, name_len);
1258 }
1259 if (*pOplock & REQ_OPLOCK)
1260 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
26f57364 1261 else if (*pOplock & REQ_BATCHOPLOCK)
1da177e4 1262 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1da177e4
LT
1263 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1264 pSMB->AllocationSize = 0;
eda3c029
SF
1265 /* set file as system file if special file such
1266 as fifo and server expecting SFU style and
1267 no Unix extensions */
790fe579 1268 if (create_options & CREATE_OPTION_SPECIAL)
eda3c029
SF
1269 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1270 else
1271 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
67750fb9 1272
1da177e4
LT
1273 /* XP does not handle ATTR_POSIX_SEMANTICS */
1274 /* but it helps speed up case sensitive checks for other
1275 servers such as Samba */
1276 if (tcon->ses->capabilities & CAP_UNIX)
1277 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1278
67750fb9
JL
1279 if (create_options & CREATE_OPTION_READONLY)
1280 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1281
1da177e4
LT
1282 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1283 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
eda3c029 1284 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
09d1db5c
SF
1285 /* BB Expirement with various impersonation levels and verify */
1286 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1da177e4
LT
1287 pSMB->SecurityFlags =
1288 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1289
1290 count += name_len;
1291 pSMB->hdr.smb_buf_length += count;
1292
1293 pSMB->ByteCount = cpu_to_le16(count);
1294 /* long_op set to 1 to allow for oplock break timeouts */
1295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef 1296 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
a4544347 1297 cifs_stats_inc(&tcon->num_opens);
1da177e4 1298 if (rc) {
b6b38f70 1299 cFYI(1, "Error in Open = %d", rc);
1da177e4 1300 } else {
09d1db5c 1301 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1da177e4
LT
1302 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1303 /* Let caller know file was created so we can set the mode. */
1304 /* Do we care about the CreateAction in any other cases? */
790fe579 1305 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
50c2f753 1306 *pOplock |= CIFS_CREATE_ACTION;
790fe579 1307 if (pfile_info) {
61e74801
SF
1308 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1309 36 /* CreationTime to Attributes */);
1310 /* the file_info buf is endian converted by caller */
1311 pfile_info->AllocationSize = pSMBr->AllocationSize;
1312 pfile_info->EndOfFile = pSMBr->EndOfFile;
1313 pfile_info->NumberOfLinks = cpu_to_le32(1);
1314 pfile_info->DeletePending = 0;
1da177e4 1315 }
1da177e4 1316 }
a5a2b489 1317
1da177e4
LT
1318 cifs_buf_release(pSMB);
1319 if (rc == -EAGAIN)
1320 goto openRetry;
1321 return rc;
1322}
1323
1da177e4 1324int
50c2f753
SF
1325CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1326 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1327 char **buf, int *pbuf_type)
1da177e4
LT
1328{
1329 int rc = -EACCES;
1330 READ_REQ *pSMB = NULL;
1331 READ_RSP *pSMBr = NULL;
1332 char *pReadData = NULL;
bfa0d75a 1333 int wct;
ec637e3f
SF
1334 int resp_buf_type = 0;
1335 struct kvec iov[1];
1da177e4 1336
b6b38f70 1337 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
790fe579 1338 if (tcon->ses->capabilities & CAP_LARGE_FILES)
bfa0d75a 1339 wct = 12;
4c3130ef 1340 else {
bfa0d75a 1341 wct = 10; /* old style read */
4c3130ef
SF
1342 if ((lseek >> 32) > 0) {
1343 /* can not handle this big offset for old */
1344 return -EIO;
1345 }
1346 }
1da177e4
LT
1347
1348 *nbytes = 0;
ec637e3f 1349 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1da177e4
LT
1350 if (rc)
1351 return rc;
1352
1353 /* tcon and ses pointer are checked in smb_init */
1354 if (tcon->ses->server == NULL)
1355 return -ECONNABORTED;
1356
ec637e3f 1357 pSMB->AndXCommand = 0xFF; /* none */
1da177e4
LT
1358 pSMB->Fid = netfid;
1359 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
790fe579 1360 if (wct == 12)
bfa0d75a 1361 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
bfa0d75a 1362
1da177e4
LT
1363 pSMB->Remaining = 0;
1364 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1365 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
790fe579 1366 if (wct == 12)
bfa0d75a
SF
1367 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1368 else {
1369 /* old style read */
50c2f753 1370 struct smb_com_readx_req *pSMBW =
bfa0d75a 1371 (struct smb_com_readx_req *)pSMB;
ec637e3f 1372 pSMBW->ByteCount = 0;
bfa0d75a 1373 }
ec637e3f
SF
1374
1375 iov[0].iov_base = (char *)pSMB;
1376 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
a761ac57 1377 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
133672ef 1378 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
a4544347 1379 cifs_stats_inc(&tcon->num_reads);
ec637e3f 1380 pSMBr = (READ_RSP *)iov[0].iov_base;
1da177e4 1381 if (rc) {
b6b38f70 1382 cERROR(1, "Send error in read = %d", rc);
1da177e4
LT
1383 } else {
1384 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1385 data_length = data_length << 16;
1386 data_length += le16_to_cpu(pSMBr->DataLength);
1387 *nbytes = data_length;
1388
1389 /*check that DataLength would not go beyond end of SMB */
ec637e3f 1390 if ((data_length > CIFSMaxBufSize)
1da177e4 1391 || (data_length > count)) {
b6b38f70
JP
1392 cFYI(1, "bad length %d for count %d",
1393 data_length, count);
1da177e4
LT
1394 rc = -EIO;
1395 *nbytes = 0;
1396 } else {
ec637e3f 1397 pReadData = (char *) (&pSMBr->hdr.Protocol) +
26f57364
SF
1398 le16_to_cpu(pSMBr->DataOffset);
1399/* if (rc = copy_to_user(buf, pReadData, data_length)) {
b6b38f70 1400 cERROR(1, "Faulting on read rc = %d",rc);
50c2f753 1401 rc = -EFAULT;
26f57364 1402 }*/ /* can not use copy_to_user when using page cache*/
790fe579 1403 if (*buf)
50c2f753 1404 memcpy(*buf, pReadData, data_length);
1da177e4
LT
1405 }
1406 }
1da177e4 1407
4b8f930f 1408/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
790fe579
SF
1409 if (*buf) {
1410 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1411 cifs_small_buf_release(iov[0].iov_base);
790fe579 1412 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1413 cifs_buf_release(iov[0].iov_base);
790fe579 1414 } else if (resp_buf_type != CIFS_NO_BUFFER) {
50c2f753
SF
1415 /* return buffer to caller to free */
1416 *buf = iov[0].iov_base;
790fe579 1417 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1418 *pbuf_type = CIFS_SMALL_BUFFER;
790fe579 1419 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1420 *pbuf_type = CIFS_LARGE_BUFFER;
6cec2aed 1421 } /* else no valid buffer on return - leave as null */
ec637e3f
SF
1422
1423 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1424 since file handle passed in no longer valid */
1425 return rc;
1426}
1427
ec637e3f 1428
1da177e4
LT
1429int
1430CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1431 const int netfid, const unsigned int count,
1432 const __u64 offset, unsigned int *nbytes, const char *buf,
50c2f753 1433 const char __user *ubuf, const int long_op)
1da177e4
LT
1434{
1435 int rc = -EACCES;
1436 WRITE_REQ *pSMB = NULL;
1437 WRITE_RSP *pSMBr = NULL;
1c955187 1438 int bytes_returned, wct;
1da177e4
LT
1439 __u32 bytes_sent;
1440 __u16 byte_count;
1441
a24e2d7d
SF
1442 *nbytes = 0;
1443
b6b38f70 1444 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
790fe579 1445 if (tcon->ses == NULL)
1c955187
SF
1446 return -ECONNABORTED;
1447
790fe579 1448 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1c955187 1449 wct = 14;
4c3130ef 1450 else {
1c955187 1451 wct = 12;
4c3130ef
SF
1452 if ((offset >> 32) > 0) {
1453 /* can not handle big offset for old srv */
1454 return -EIO;
1455 }
1456 }
1c955187
SF
1457
1458 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1da177e4
LT
1459 (void **) &pSMBr);
1460 if (rc)
1461 return rc;
1462 /* tcon and ses pointer are checked in smb_init */
1463 if (tcon->ses->server == NULL)
1464 return -ECONNABORTED;
1465
1466 pSMB->AndXCommand = 0xFF; /* none */
1467 pSMB->Fid = netfid;
1468 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
790fe579 1469 if (wct == 14)
1c955187 1470 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
50c2f753 1471
1da177e4
LT
1472 pSMB->Reserved = 0xFFFFFFFF;
1473 pSMB->WriteMode = 0;
1474 pSMB->Remaining = 0;
1475
50c2f753 1476 /* Can increase buffer size if buffer is big enough in some cases ie we
1da177e4
LT
1477 can send more if LARGE_WRITE_X capability returned by the server and if
1478 our buffer is big enough or if we convert to iovecs on socket writes
1479 and eliminate the copy to the CIFS buffer */
790fe579 1480 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1da177e4
LT
1481 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1482 } else {
1483 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1484 & ~0xFF;
1485 }
1486
1487 if (bytes_sent > count)
1488 bytes_sent = count;
1489 pSMB->DataOffset =
50c2f753 1490 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
790fe579 1491 if (buf)
61e74801 1492 memcpy(pSMB->Data, buf, bytes_sent);
790fe579
SF
1493 else if (ubuf) {
1494 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1da177e4
LT
1495 cifs_buf_release(pSMB);
1496 return -EFAULT;
1497 }
e30dcf3a 1498 } else if (count != 0) {
1da177e4
LT
1499 /* No buffer */
1500 cifs_buf_release(pSMB);
1501 return -EINVAL;
e30dcf3a 1502 } /* else setting file size with write of zero bytes */
790fe579 1503 if (wct == 14)
e30dcf3a 1504 byte_count = bytes_sent + 1; /* pad */
ad7a2926 1505 else /* wct == 12 */
e30dcf3a 1506 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
ad7a2926 1507
1da177e4
LT
1508 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1509 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
e30dcf3a 1510 pSMB->hdr.smb_buf_length += byte_count;
1c955187 1511
790fe579 1512 if (wct == 14)
1c955187 1513 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753
SF
1514 else { /* old style write has byte count 4 bytes earlier
1515 so 4 bytes pad */
1516 struct smb_com_writex_req *pSMBW =
1c955187
SF
1517 (struct smb_com_writex_req *)pSMB;
1518 pSMBW->ByteCount = cpu_to_le16(byte_count);
1519 }
1da177e4
LT
1520
1521 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1522 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
a4544347 1523 cifs_stats_inc(&tcon->num_writes);
1da177e4 1524 if (rc) {
f19159dc 1525 cFYI(1, "Send error in write = %d", rc);
1da177e4
LT
1526 } else {
1527 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1528 *nbytes = (*nbytes) << 16;
1529 *nbytes += le16_to_cpu(pSMBr->Count);
6513a81e
SJ
1530
1531 /*
1532 * Mask off high 16 bits when bytes written as returned by the
1533 * server is greater than bytes requested by the client. Some
1534 * OS/2 servers are known to set incorrect CountHigh values.
1535 */
1536 if (*nbytes > count)
1537 *nbytes &= 0xFFFF;
1da177e4
LT
1538 }
1539
1540 cifs_buf_release(pSMB);
1541
50c2f753 1542 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1543 since file handle passed in no longer valid */
1544
1545 return rc;
1546}
1547
d6e04ae6
SF
1548int
1549CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1da177e4 1550 const int netfid, const unsigned int count,
3e84469d
SF
1551 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1552 int n_vec, const int long_op)
1da177e4
LT
1553{
1554 int rc = -EACCES;
1555 WRITE_REQ *pSMB = NULL;
ec637e3f 1556 int wct;
d6e04ae6 1557 int smb_hdr_len;
ec637e3f 1558 int resp_buf_type = 0;
1da177e4 1559
fbec9ab9
JL
1560 *nbytes = 0;
1561
b6b38f70 1562 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
ff7feac9 1563
4c3130ef 1564 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
8cc64c6e 1565 wct = 14;
4c3130ef 1566 } else {
8cc64c6e 1567 wct = 12;
4c3130ef
SF
1568 if ((offset >> 32) > 0) {
1569 /* can not handle big offset for old srv */
1570 return -EIO;
1571 }
1572 }
8cc64c6e 1573 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1da177e4
LT
1574 if (rc)
1575 return rc;
1da177e4
LT
1576 /* tcon and ses pointer are checked in smb_init */
1577 if (tcon->ses->server == NULL)
1578 return -ECONNABORTED;
1579
d6e04ae6 1580 pSMB->AndXCommand = 0xFF; /* none */
1da177e4
LT
1581 pSMB->Fid = netfid;
1582 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
790fe579 1583 if (wct == 14)
8cc64c6e 1584 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1da177e4
LT
1585 pSMB->Reserved = 0xFFFFFFFF;
1586 pSMB->WriteMode = 0;
1587 pSMB->Remaining = 0;
d6e04ae6 1588
1da177e4 1589 pSMB->DataOffset =
50c2f753 1590 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1da177e4 1591
3e84469d
SF
1592 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1593 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
d6e04ae6 1594 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
790fe579 1595 if (wct == 14)
8cc64c6e
SF
1596 pSMB->hdr.smb_buf_length += count+1;
1597 else /* wct == 12 */
790fe579
SF
1598 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1599 if (wct == 14)
8cc64c6e
SF
1600 pSMB->ByteCount = cpu_to_le16(count + 1);
1601 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
50c2f753 1602 struct smb_com_writex_req *pSMBW =
8cc64c6e
SF
1603 (struct smb_com_writex_req *)pSMB;
1604 pSMBW->ByteCount = cpu_to_le16(count + 5);
1605 }
3e84469d 1606 iov[0].iov_base = pSMB;
790fe579 1607 if (wct == 14)
ec637e3f
SF
1608 iov[0].iov_len = smb_hdr_len + 4;
1609 else /* wct == 12 pad bigger by four bytes */
1610 iov[0].iov_len = smb_hdr_len + 8;
50c2f753 1611
1da177e4 1612
ec637e3f 1613 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
133672ef 1614 long_op);
a4544347 1615 cifs_stats_inc(&tcon->num_writes);
1da177e4 1616 if (rc) {
b6b38f70 1617 cFYI(1, "Send error Write2 = %d", rc);
790fe579 1618 } else if (resp_buf_type == 0) {
ec637e3f
SF
1619 /* presumably this can not happen, but best to be safe */
1620 rc = -EIO;
d6e04ae6 1621 } else {
ad7a2926 1622 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
d6e04ae6
SF
1623 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1624 *nbytes = (*nbytes) << 16;
1625 *nbytes += le16_to_cpu(pSMBr->Count);
6513a81e
SJ
1626
1627 /*
1628 * Mask off high 16 bits when bytes written as returned by the
1629 * server is greater than bytes requested by the client. OS/2
1630 * servers are known to set incorrect CountHigh values.
1631 */
1632 if (*nbytes > count)
1633 *nbytes &= 0xFFFF;
50c2f753 1634 }
1da177e4 1635
4b8f930f 1636/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
790fe579 1637 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1638 cifs_small_buf_release(iov[0].iov_base);
790fe579 1639 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1640 cifs_buf_release(iov[0].iov_base);
1da177e4 1641
50c2f753 1642 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1643 since file handle passed in no longer valid */
1644
1645 return rc;
1646}
d6e04ae6
SF
1647
1648
1da177e4
LT
1649int
1650CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1651 const __u16 smb_file_id, const __u64 len,
1652 const __u64 offset, const __u32 numUnlock,
4b18f2a9 1653 const __u32 numLock, const __u8 lockType, const bool waitFlag)
1da177e4
LT
1654{
1655 int rc = 0;
1656 LOCK_REQ *pSMB = NULL;
aaa9bbe0 1657/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1da177e4
LT
1658 int bytes_returned;
1659 int timeout = 0;
1660 __u16 count;
1661
b6b38f70 1662 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
46810cbf
SF
1663 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1664
1da177e4
LT
1665 if (rc)
1666 return rc;
1667
790fe579 1668 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
133672ef 1669 timeout = CIFS_ASYNC_OP; /* no response expected */
1da177e4 1670 pSMB->Timeout = 0;
4b18f2a9 1671 } else if (waitFlag) {
133672ef 1672 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1da177e4
LT
1673 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1674 } else {
1675 pSMB->Timeout = 0;
1676 }
1677
1678 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1679 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1680 pSMB->LockType = lockType;
1681 pSMB->AndXCommand = 0xFF; /* none */
1682 pSMB->Fid = smb_file_id; /* netfid stays le */
1683
790fe579 1684 if ((numLock != 0) || (numUnlock != 0)) {
1da177e4
LT
1685 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1686 /* BB where to store pid high? */
1687 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1688 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1689 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1690 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1691 count = sizeof(LOCKING_ANDX_RANGE);
1692 } else {
1693 /* oplock break */
1694 count = 0;
1695 }
1696 pSMB->hdr.smb_buf_length += count;
1697 pSMB->ByteCount = cpu_to_le16(count);
1698
7ee1af76
JA
1699 if (waitFlag) {
1700 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
aaa9bbe0 1701 (struct smb_hdr *) pSMB, &bytes_returned);
133672ef 1702 cifs_small_buf_release(pSMB);
7ee1af76 1703 } else {
133672ef
SF
1704 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1705 timeout);
1706 /* SMB buffer freed by function above */
7ee1af76 1707 }
a4544347 1708 cifs_stats_inc(&tcon->num_locks);
ad7a2926 1709 if (rc)
b6b38f70 1710 cFYI(1, "Send error in Lock = %d", rc);
1da177e4 1711
50c2f753 1712 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1713 since file handle passed in no longer valid */
1714 return rc;
1715}
1716
08547b03
SF
1717int
1718CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1719 const __u16 smb_file_id, const int get_flag, const __u64 len,
50c2f753 1720 struct file_lock *pLockData, const __u16 lock_type,
4b18f2a9 1721 const bool waitFlag)
08547b03
SF
1722{
1723 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1724 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
08547b03
SF
1725 struct cifs_posix_lock *parm_data;
1726 int rc = 0;
3a5ff61c 1727 int timeout = 0;
08547b03 1728 int bytes_returned = 0;
133672ef 1729 int resp_buf_type = 0;
08547b03 1730 __u16 params, param_offset, offset, byte_count, count;
133672ef 1731 struct kvec iov[1];
08547b03 1732
b6b38f70 1733 cFYI(1, "Posix Lock");
fc94cdb9 1734
790fe579 1735 if (pLockData == NULL)
ed5f0370 1736 return -EINVAL;
fc94cdb9 1737
08547b03
SF
1738 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1739
1740 if (rc)
1741 return rc;
1742
1743 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1744
50c2f753 1745 params = 6;
08547b03
SF
1746 pSMB->MaxSetupCount = 0;
1747 pSMB->Reserved = 0;
1748 pSMB->Flags = 0;
08547b03
SF
1749 pSMB->Reserved2 = 0;
1750 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1751 offset = param_offset + params;
1752
08547b03
SF
1753 count = sizeof(struct cifs_posix_lock);
1754 pSMB->MaxParameterCount = cpu_to_le16(2);
ad7a2926 1755 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
08547b03
SF
1756 pSMB->SetupCount = 1;
1757 pSMB->Reserved3 = 0;
790fe579 1758 if (get_flag)
08547b03
SF
1759 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1760 else
1761 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1762 byte_count = 3 /* pad */ + params + count;
1763 pSMB->DataCount = cpu_to_le16(count);
1764 pSMB->ParameterCount = cpu_to_le16(params);
1765 pSMB->TotalDataCount = pSMB->DataCount;
1766 pSMB->TotalParameterCount = pSMB->ParameterCount;
1767 pSMB->ParameterOffset = cpu_to_le16(param_offset);
50c2f753 1768 parm_data = (struct cifs_posix_lock *)
08547b03
SF
1769 (((char *) &pSMB->hdr.Protocol) + offset);
1770
1771 parm_data->lock_type = cpu_to_le16(lock_type);
790fe579 1772 if (waitFlag) {
133672ef 1773 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
cec6815a 1774 parm_data->lock_flags = cpu_to_le16(1);
3a5ff61c
SF
1775 pSMB->Timeout = cpu_to_le32(-1);
1776 } else
1777 pSMB->Timeout = 0;
1778
08547b03 1779 parm_data->pid = cpu_to_le32(current->tgid);
fc94cdb9 1780 parm_data->start = cpu_to_le64(pLockData->fl_start);
cec6815a 1781 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
08547b03
SF
1782
1783 pSMB->DataOffset = cpu_to_le16(offset);
f26282c9 1784 pSMB->Fid = smb_file_id;
08547b03
SF
1785 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1786 pSMB->Reserved4 = 0;
1787 pSMB->hdr.smb_buf_length += byte_count;
1788 pSMB->ByteCount = cpu_to_le16(byte_count);
7ee1af76
JA
1789 if (waitFlag) {
1790 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1791 (struct smb_hdr *) pSMBr, &bytes_returned);
1792 } else {
133672ef
SF
1793 iov[0].iov_base = (char *)pSMB;
1794 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1795 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1796 &resp_buf_type, timeout);
1797 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1798 not try to free it twice below on exit */
1799 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
7ee1af76
JA
1800 }
1801
08547b03 1802 if (rc) {
b6b38f70 1803 cFYI(1, "Send error in Posix Lock = %d", rc);
fc94cdb9
SF
1804 } else if (get_flag) {
1805 /* lock structure can be returned on get */
1806 __u16 data_offset;
1807 __u16 data_count;
1808 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1809
1810 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1811 rc = -EIO; /* bad smb */
1812 goto plk_err_exit;
1813 }
fc94cdb9
SF
1814 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1815 data_count = le16_to_cpu(pSMBr->t2.DataCount);
790fe579 1816 if (data_count < sizeof(struct cifs_posix_lock)) {
fc94cdb9
SF
1817 rc = -EIO;
1818 goto plk_err_exit;
1819 }
1820 parm_data = (struct cifs_posix_lock *)
1821 ((char *)&pSMBr->hdr.Protocol + data_offset);
f05337c6 1822 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
fc94cdb9 1823 pLockData->fl_type = F_UNLCK;
f05337c6
PS
1824 else {
1825 if (parm_data->lock_type ==
1826 __constant_cpu_to_le16(CIFS_RDLCK))
1827 pLockData->fl_type = F_RDLCK;
1828 else if (parm_data->lock_type ==
1829 __constant_cpu_to_le16(CIFS_WRLCK))
1830 pLockData->fl_type = F_WRLCK;
1831
1832 pLockData->fl_start = parm_data->start;
1833 pLockData->fl_end = parm_data->start +
1834 parm_data->length - 1;
1835 pLockData->fl_pid = parm_data->pid;
1836 }
08547b03 1837 }
50c2f753 1838
fc94cdb9 1839plk_err_exit:
08547b03
SF
1840 if (pSMB)
1841 cifs_small_buf_release(pSMB);
1842
133672ef
SF
1843 if (resp_buf_type == CIFS_SMALL_BUFFER)
1844 cifs_small_buf_release(iov[0].iov_base);
1845 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1846 cifs_buf_release(iov[0].iov_base);
1847
08547b03
SF
1848 /* Note: On -EAGAIN error only caller can retry on handle based calls
1849 since file handle passed in no longer valid */
1850
1851 return rc;
1852}
1853
1854
1da177e4
LT
1855int
1856CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1857{
1858 int rc = 0;
1859 CLOSE_REQ *pSMB = NULL;
b6b38f70 1860 cFYI(1, "In CIFSSMBClose");
1da177e4
LT
1861
1862/* do not retry on dead session on close */
1863 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
790fe579 1864 if (rc == -EAGAIN)
1da177e4
LT
1865 return 0;
1866 if (rc)
1867 return rc;
1868
1da177e4 1869 pSMB->FileID = (__u16) smb_file_id;
b815f1e5 1870 pSMB->LastWriteTime = 0xFFFFFFFF;
1da177e4 1871 pSMB->ByteCount = 0;
133672ef 1872 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
a4544347 1873 cifs_stats_inc(&tcon->num_closes);
1da177e4 1874 if (rc) {
790fe579 1875 if (rc != -EINTR) {
1da177e4 1876 /* EINTR is expected when user ctl-c to kill app */
b6b38f70 1877 cERROR(1, "Send error in Close = %d", rc);
1da177e4
LT
1878 }
1879 }
1880
1da177e4 1881 /* Since session is dead, file will be closed on server already */
790fe579 1882 if (rc == -EAGAIN)
1da177e4
LT
1883 rc = 0;
1884
1885 return rc;
1886}
1887
b298f223
SF
1888int
1889CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1890{
1891 int rc = 0;
1892 FLUSH_REQ *pSMB = NULL;
b6b38f70 1893 cFYI(1, "In CIFSSMBFlush");
b298f223
SF
1894
1895 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1896 if (rc)
1897 return rc;
1898
1899 pSMB->FileID = (__u16) smb_file_id;
1900 pSMB->ByteCount = 0;
1901 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1902 cifs_stats_inc(&tcon->num_flushes);
1903 if (rc)
b6b38f70 1904 cERROR(1, "Send error in Flush = %d", rc);
b298f223
SF
1905
1906 return rc;
1907}
1908
1da177e4
LT
1909int
1910CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1911 const char *fromName, const char *toName,
737b758c 1912 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1913{
1914 int rc = 0;
1915 RENAME_REQ *pSMB = NULL;
1916 RENAME_RSP *pSMBr = NULL;
1917 int bytes_returned;
1918 int name_len, name_len2;
1919 __u16 count;
1920
b6b38f70 1921 cFYI(1, "In CIFSSMBRename");
1da177e4
LT
1922renameRetry:
1923 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1924 (void **) &pSMBr);
1925 if (rc)
1926 return rc;
1927
1928 pSMB->BufferFormat = 0x04;
1929 pSMB->SearchAttributes =
1930 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1931 ATTR_DIRECTORY);
1932
1933 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1934 name_len =
50c2f753 1935 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 1936 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1937 name_len++; /* trailing null */
1938 name_len *= 2;
1939 pSMB->OldFileName[name_len] = 0x04; /* pad */
1940 /* protocol requires ASCII signature byte on Unicode string */
1941 pSMB->OldFileName[name_len + 1] = 0x00;
1942 name_len2 =
582d21e5 1943 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 1944 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1945 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1946 name_len2 *= 2; /* convert to bytes */
50c2f753 1947 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
1948 name_len = strnlen(fromName, PATH_MAX);
1949 name_len++; /* trailing null */
1950 strncpy(pSMB->OldFileName, fromName, name_len);
1951 name_len2 = strnlen(toName, PATH_MAX);
1952 name_len2++; /* trailing null */
1953 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1954 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1955 name_len2++; /* trailing null */
1956 name_len2++; /* signature byte */
1957 }
1958
1959 count = 1 /* 1st signature byte */ + name_len + name_len2;
1960 pSMB->hdr.smb_buf_length += count;
1961 pSMB->ByteCount = cpu_to_le16(count);
1962
1963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1965 cifs_stats_inc(&tcon->num_renames);
ad7a2926 1966 if (rc)
b6b38f70 1967 cFYI(1, "Send error in rename = %d", rc);
1da177e4 1968
1da177e4
LT
1969 cifs_buf_release(pSMB);
1970
1971 if (rc == -EAGAIN)
1972 goto renameRetry;
1973
1974 return rc;
1975}
1976
50c2f753 1977int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
391e5755 1978 int netfid, const char *target_name,
50c2f753 1979 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1980{
1981 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1982 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
50c2f753 1983 struct set_file_rename *rename_info;
1da177e4
LT
1984 char *data_offset;
1985 char dummy_string[30];
1986 int rc = 0;
1987 int bytes_returned = 0;
1988 int len_of_str;
1989 __u16 params, param_offset, offset, count, byte_count;
1990
b6b38f70 1991 cFYI(1, "Rename to File by handle");
1da177e4
LT
1992 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1993 (void **) &pSMBr);
1994 if (rc)
1995 return rc;
1996
1997 params = 6;
1998 pSMB->MaxSetupCount = 0;
1999 pSMB->Reserved = 0;
2000 pSMB->Flags = 0;
2001 pSMB->Timeout = 0;
2002 pSMB->Reserved2 = 0;
2003 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2004 offset = param_offset + params;
2005
2006 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2007 rename_info = (struct set_file_rename *) data_offset;
2008 pSMB->MaxParameterCount = cpu_to_le16(2);
ad7a2926 2009 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1da177e4
LT
2010 pSMB->SetupCount = 1;
2011 pSMB->Reserved3 = 0;
2012 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2013 byte_count = 3 /* pad */ + params;
2014 pSMB->ParameterCount = cpu_to_le16(params);
2015 pSMB->TotalParameterCount = pSMB->ParameterCount;
2016 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2017 pSMB->DataOffset = cpu_to_le16(offset);
2018 /* construct random name ".cifs_tmp<inodenum><mid>" */
2019 rename_info->overwrite = cpu_to_le32(1);
2020 rename_info->root_fid = 0;
2021 /* unicode only call */
790fe579 2022 if (target_name == NULL) {
50c2f753
SF
2023 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2024 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
737b758c 2025 dummy_string, 24, nls_codepage, remap);
1da177e4 2026 } else {
b1a45695 2027 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
50c2f753
SF
2028 target_name, PATH_MAX, nls_codepage,
2029 remap);
1da177e4
LT
2030 }
2031 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
391e5755 2032 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
1da177e4
LT
2033 byte_count += count;
2034 pSMB->DataCount = cpu_to_le16(count);
2035 pSMB->TotalDataCount = pSMB->DataCount;
2036 pSMB->Fid = netfid;
2037 pSMB->InformationLevel =
2038 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2039 pSMB->Reserved4 = 0;
2040 pSMB->hdr.smb_buf_length += byte_count;
2041 pSMB->ByteCount = cpu_to_le16(byte_count);
2042 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
50c2f753 2043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2044 cifs_stats_inc(&pTcon->num_t2renames);
ad7a2926 2045 if (rc)
b6b38f70 2046 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
a5a2b489 2047
1da177e4
LT
2048 cifs_buf_release(pSMB);
2049
2050 /* Note: On -EAGAIN error only caller can retry on handle based calls
2051 since file handle passed in no longer valid */
2052
2053 return rc;
2054}
2055
2056int
50c2f753
SF
2057CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2058 const __u16 target_tid, const char *toName, const int flags,
2059 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2060{
2061 int rc = 0;
2062 COPY_REQ *pSMB = NULL;
2063 COPY_RSP *pSMBr = NULL;
2064 int bytes_returned;
2065 int name_len, name_len2;
2066 __u16 count;
2067
b6b38f70 2068 cFYI(1, "In CIFSSMBCopy");
1da177e4
LT
2069copyRetry:
2070 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2071 (void **) &pSMBr);
2072 if (rc)
2073 return rc;
2074
2075 pSMB->BufferFormat = 0x04;
2076 pSMB->Tid2 = target_tid;
2077
2078 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2079
2080 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
50c2f753 2081 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
737b758c
SF
2082 fromName, PATH_MAX, nls_codepage,
2083 remap);
1da177e4
LT
2084 name_len++; /* trailing null */
2085 name_len *= 2;
2086 pSMB->OldFileName[name_len] = 0x04; /* pad */
2087 /* protocol requires ASCII signature byte on Unicode string */
2088 pSMB->OldFileName[name_len + 1] = 0x00;
50c2f753
SF
2089 name_len2 =
2090 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 2091 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2092 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2093 name_len2 *= 2; /* convert to bytes */
50c2f753 2094 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2095 name_len = strnlen(fromName, PATH_MAX);
2096 name_len++; /* trailing null */
2097 strncpy(pSMB->OldFileName, fromName, name_len);
2098 name_len2 = strnlen(toName, PATH_MAX);
2099 name_len2++; /* trailing null */
2100 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2101 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2102 name_len2++; /* trailing null */
2103 name_len2++; /* signature byte */
2104 }
2105
2106 count = 1 /* 1st signature byte */ + name_len + name_len2;
2107 pSMB->hdr.smb_buf_length += count;
2108 pSMB->ByteCount = cpu_to_le16(count);
2109
2110 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2111 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2112 if (rc) {
b6b38f70
JP
2113 cFYI(1, "Send error in copy = %d with %d files copied",
2114 rc, le16_to_cpu(pSMBr->CopyCount));
1da177e4 2115 }
0d817bc0 2116 cifs_buf_release(pSMB);
1da177e4
LT
2117
2118 if (rc == -EAGAIN)
2119 goto copyRetry;
2120
2121 return rc;
2122}
2123
2124int
2125CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2126 const char *fromName, const char *toName,
2127 const struct nls_table *nls_codepage)
2128{
2129 TRANSACTION2_SPI_REQ *pSMB = NULL;
2130 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2131 char *data_offset;
2132 int name_len;
2133 int name_len_target;
2134 int rc = 0;
2135 int bytes_returned = 0;
2136 __u16 params, param_offset, offset, byte_count;
2137
b6b38f70 2138 cFYI(1, "In Symlink Unix style");
1da177e4
LT
2139createSymLinkRetry:
2140 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2141 (void **) &pSMBr);
2142 if (rc)
2143 return rc;
2144
2145 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2146 name_len =
e89dc920 2147 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
1da177e4
LT
2148 /* find define for this maxpathcomponent */
2149 , nls_codepage);
2150 name_len++; /* trailing null */
2151 name_len *= 2;
2152
50c2f753 2153 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2154 name_len = strnlen(fromName, PATH_MAX);
2155 name_len++; /* trailing null */
2156 strncpy(pSMB->FileName, fromName, name_len);
2157 }
2158 params = 6 + name_len;
2159 pSMB->MaxSetupCount = 0;
2160 pSMB->Reserved = 0;
2161 pSMB->Flags = 0;
2162 pSMB->Timeout = 0;
2163 pSMB->Reserved2 = 0;
2164 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2165 InformationLevel) - 4;
1da177e4
LT
2166 offset = param_offset + params;
2167
2168 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2169 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2170 name_len_target =
e89dc920 2171 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
1da177e4
LT
2172 /* find define for this maxpathcomponent */
2173 , nls_codepage);
2174 name_len_target++; /* trailing null */
2175 name_len_target *= 2;
50c2f753 2176 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2177 name_len_target = strnlen(toName, PATH_MAX);
2178 name_len_target++; /* trailing null */
2179 strncpy(data_offset, toName, name_len_target);
2180 }
2181
2182 pSMB->MaxParameterCount = cpu_to_le16(2);
2183 /* BB find exact max on data count below from sess */
2184 pSMB->MaxDataCount = cpu_to_le16(1000);
2185 pSMB->SetupCount = 1;
2186 pSMB->Reserved3 = 0;
2187 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2188 byte_count = 3 /* pad */ + params + name_len_target;
2189 pSMB->DataCount = cpu_to_le16(name_len_target);
2190 pSMB->ParameterCount = cpu_to_le16(params);
2191 pSMB->TotalDataCount = pSMB->DataCount;
2192 pSMB->TotalParameterCount = pSMB->ParameterCount;
2193 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2194 pSMB->DataOffset = cpu_to_le16(offset);
2195 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2196 pSMB->Reserved4 = 0;
2197 pSMB->hdr.smb_buf_length += byte_count;
2198 pSMB->ByteCount = cpu_to_le16(byte_count);
2199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2201 cifs_stats_inc(&tcon->num_symlinks);
ad7a2926 2202 if (rc)
b6b38f70 2203 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
1da177e4 2204
0d817bc0 2205 cifs_buf_release(pSMB);
1da177e4
LT
2206
2207 if (rc == -EAGAIN)
2208 goto createSymLinkRetry;
2209
2210 return rc;
2211}
2212
2213int
2214CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2215 const char *fromName, const char *toName,
737b758c 2216 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2217{
2218 TRANSACTION2_SPI_REQ *pSMB = NULL;
2219 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2220 char *data_offset;
2221 int name_len;
2222 int name_len_target;
2223 int rc = 0;
2224 int bytes_returned = 0;
2225 __u16 params, param_offset, offset, byte_count;
2226
b6b38f70 2227 cFYI(1, "In Create Hard link Unix style");
1da177e4
LT
2228createHardLinkRetry:
2229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2230 (void **) &pSMBr);
2231 if (rc)
2232 return rc;
2233
2234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
b1a45695 2235 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
737b758c 2236 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2237 name_len++; /* trailing null */
2238 name_len *= 2;
2239
50c2f753 2240 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2241 name_len = strnlen(toName, PATH_MAX);
2242 name_len++; /* trailing null */
2243 strncpy(pSMB->FileName, toName, name_len);
2244 }
2245 params = 6 + name_len;
2246 pSMB->MaxSetupCount = 0;
2247 pSMB->Reserved = 0;
2248 pSMB->Flags = 0;
2249 pSMB->Timeout = 0;
2250 pSMB->Reserved2 = 0;
2251 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2252 InformationLevel) - 4;
1da177e4
LT
2253 offset = param_offset + params;
2254
2255 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2256 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2257 name_len_target =
b1a45695 2258 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
737b758c 2259 nls_codepage, remap);
1da177e4
LT
2260 name_len_target++; /* trailing null */
2261 name_len_target *= 2;
50c2f753 2262 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2263 name_len_target = strnlen(fromName, PATH_MAX);
2264 name_len_target++; /* trailing null */
2265 strncpy(data_offset, fromName, name_len_target);
2266 }
2267
2268 pSMB->MaxParameterCount = cpu_to_le16(2);
2269 /* BB find exact max on data count below from sess*/
2270 pSMB->MaxDataCount = cpu_to_le16(1000);
2271 pSMB->SetupCount = 1;
2272 pSMB->Reserved3 = 0;
2273 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2274 byte_count = 3 /* pad */ + params + name_len_target;
2275 pSMB->ParameterCount = cpu_to_le16(params);
2276 pSMB->TotalParameterCount = pSMB->ParameterCount;
2277 pSMB->DataCount = cpu_to_le16(name_len_target);
2278 pSMB->TotalDataCount = pSMB->DataCount;
2279 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2280 pSMB->DataOffset = cpu_to_le16(offset);
2281 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2282 pSMB->Reserved4 = 0;
2283 pSMB->hdr.smb_buf_length += byte_count;
2284 pSMB->ByteCount = cpu_to_le16(byte_count);
2285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2287 cifs_stats_inc(&tcon->num_hardlinks);
ad7a2926 2288 if (rc)
b6b38f70 2289 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
1da177e4
LT
2290
2291 cifs_buf_release(pSMB);
2292 if (rc == -EAGAIN)
2293 goto createHardLinkRetry;
2294
2295 return rc;
2296}
2297
2298int
2299CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2300 const char *fromName, const char *toName,
737b758c 2301 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2302{
2303 int rc = 0;
2304 NT_RENAME_REQ *pSMB = NULL;
2305 RENAME_RSP *pSMBr = NULL;
2306 int bytes_returned;
2307 int name_len, name_len2;
2308 __u16 count;
2309
b6b38f70 2310 cFYI(1, "In CIFSCreateHardLink");
1da177e4
LT
2311winCreateHardLinkRetry:
2312
2313 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2314 (void **) &pSMBr);
2315 if (rc)
2316 return rc;
2317
2318 pSMB->SearchAttributes =
2319 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2320 ATTR_DIRECTORY);
2321 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2322 pSMB->ClusterCount = 0;
2323
2324 pSMB->BufferFormat = 0x04;
2325
2326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2327 name_len =
b1a45695 2328 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
737b758c 2329 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2330 name_len++; /* trailing null */
2331 name_len *= 2;
fcc7c09d
JL
2332
2333 /* protocol specifies ASCII buffer format (0x04) for unicode */
2334 pSMB->OldFileName[name_len] = 0x04;
2335 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
1da177e4 2336 name_len2 =
50c2f753 2337 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
737b758c 2338 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2339 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2340 name_len2 *= 2; /* convert to bytes */
50c2f753 2341 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2342 name_len = strnlen(fromName, PATH_MAX);
2343 name_len++; /* trailing null */
2344 strncpy(pSMB->OldFileName, fromName, name_len);
2345 name_len2 = strnlen(toName, PATH_MAX);
2346 name_len2++; /* trailing null */
2347 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2348 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2349 name_len2++; /* trailing null */
2350 name_len2++; /* signature byte */
2351 }
2352
2353 count = 1 /* string type byte */ + name_len + name_len2;
2354 pSMB->hdr.smb_buf_length += count;
2355 pSMB->ByteCount = cpu_to_le16(count);
2356
2357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2359 cifs_stats_inc(&tcon->num_hardlinks);
ad7a2926 2360 if (rc)
b6b38f70 2361 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
ad7a2926 2362
1da177e4
LT
2363 cifs_buf_release(pSMB);
2364 if (rc == -EAGAIN)
2365 goto winCreateHardLinkRetry;
2366
2367 return rc;
2368}
2369
2370int
2371CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
460b9696 2372 const unsigned char *searchName, char **symlinkinfo,
1da177e4
LT
2373 const struct nls_table *nls_codepage)
2374{
2375/* SMB_QUERY_FILE_UNIX_LINK */
2376 TRANSACTION2_QPI_REQ *pSMB = NULL;
2377 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2378 int rc = 0;
2379 int bytes_returned;
2380 int name_len;
2381 __u16 params, byte_count;
460b9696 2382 char *data_start;
1da177e4 2383
b6b38f70 2384 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
1da177e4
LT
2385
2386querySymLinkRetry:
2387 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2388 (void **) &pSMBr);
2389 if (rc)
2390 return rc;
2391
2392 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2393 name_len =
50c2f753
SF
2394 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2395 PATH_MAX, nls_codepage);
1da177e4
LT
2396 name_len++; /* trailing null */
2397 name_len *= 2;
50c2f753 2398 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2399 name_len = strnlen(searchName, PATH_MAX);
2400 name_len++; /* trailing null */
2401 strncpy(pSMB->FileName, searchName, name_len);
2402 }
2403
2404 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2405 pSMB->TotalDataCount = 0;
2406 pSMB->MaxParameterCount = cpu_to_le16(2);
46a7574c 2407 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
1da177e4
LT
2408 pSMB->MaxSetupCount = 0;
2409 pSMB->Reserved = 0;
2410 pSMB->Flags = 0;
2411 pSMB->Timeout = 0;
2412 pSMB->Reserved2 = 0;
2413 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 2414 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
2415 pSMB->DataCount = 0;
2416 pSMB->DataOffset = 0;
2417 pSMB->SetupCount = 1;
2418 pSMB->Reserved3 = 0;
2419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2420 byte_count = params + 1 /* pad */ ;
2421 pSMB->TotalParameterCount = cpu_to_le16(params);
2422 pSMB->ParameterCount = pSMB->TotalParameterCount;
2423 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2424 pSMB->Reserved4 = 0;
2425 pSMB->hdr.smb_buf_length += byte_count;
2426 pSMB->ByteCount = cpu_to_le16(byte_count);
2427
2428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2430 if (rc) {
b6b38f70 2431 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
1da177e4
LT
2432 } else {
2433 /* decode response */
2434
2435 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 2436 /* BB also check enough total bytes returned */
460b9696
JL
2437 if (rc || (pSMBr->ByteCount < 2))
2438 rc = -EIO;
1da177e4 2439 else {
0e0d2cf3 2440 bool is_unicode;
460b9696
JL
2441 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2442
2443 data_start = ((char *) &pSMBr->hdr.Protocol) +
2444 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4 2445
0e0d2cf3
SF
2446 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2447 is_unicode = true;
2448 else
2449 is_unicode = false;
2450
737b758c 2451 /* BB FIXME investigate remapping reserved chars here */
d185cda7 2452 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
0e0d2cf3 2453 is_unicode, nls_codepage);
8b6427a2 2454 if (!*symlinkinfo)
460b9696 2455 rc = -ENOMEM;
1da177e4
LT
2456 }
2457 }
2458 cifs_buf_release(pSMB);
2459 if (rc == -EAGAIN)
2460 goto querySymLinkRetry;
2461 return rc;
2462}
2463
c9489779 2464#ifdef CONFIG_CIFS_EXPERIMENTAL
0a4b92c0
SF
2465/* Initialize NT TRANSACT SMB into small smb request buffer.
2466 This assumes that all NT TRANSACTS that we init here have
2467 total parm and data under about 400 bytes (to fit in small cifs
2468 buffer size), which is the case so far, it easily fits. NB:
2469 Setup words themselves and ByteCount
2470 MaxSetupCount (size of returned setup area) and
2471 MaxParameterCount (returned parms size) must be set by caller */
50c2f753 2472static int
b9c7a2bb 2473smb_init_nttransact(const __u16 sub_command, const int setup_count,
0a4b92c0 2474 const int parm_len, struct cifsTconInfo *tcon,
50c2f753 2475 void **ret_buf)
0a4b92c0
SF
2476{
2477 int rc;
2478 __u32 temp_offset;
50c2f753 2479 struct smb_com_ntransact_req *pSMB;
0a4b92c0
SF
2480
2481 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2482 (void **)&pSMB);
2483 if (rc)
2484 return rc;
2485 *ret_buf = (void *)pSMB;
2486 pSMB->Reserved = 0;
2487 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2488 pSMB->TotalDataCount = 0;
2489 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2490 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2491 pSMB->ParameterCount = pSMB->TotalParameterCount;
2492 pSMB->DataCount = pSMB->TotalDataCount;
2493 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2494 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2495 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2496 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2497 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2498 pSMB->SubCommand = cpu_to_le16(sub_command);
2499 return 0;
2500}
2501
2502static int
50c2f753 2503validate_ntransact(char *buf, char **ppparm, char **ppdata,
b9c7a2bb 2504 __u32 *pparmlen, __u32 *pdatalen)
0a4b92c0 2505{
50c2f753 2506 char *end_of_smb;
0a4b92c0 2507 __u32 data_count, data_offset, parm_count, parm_offset;
50c2f753 2508 struct smb_com_ntransact_rsp *pSMBr;
0a4b92c0 2509
630f3f0c
SF
2510 *pdatalen = 0;
2511 *pparmlen = 0;
2512
790fe579 2513 if (buf == NULL)
0a4b92c0
SF
2514 return -EINVAL;
2515
2516 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2517
2518 /* ByteCount was converted from little endian in SendReceive */
50c2f753 2519 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
0a4b92c0
SF
2520 (char *)&pSMBr->ByteCount;
2521
0a4b92c0
SF
2522 data_offset = le32_to_cpu(pSMBr->DataOffset);
2523 data_count = le32_to_cpu(pSMBr->DataCount);
50c2f753 2524 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
0a4b92c0
SF
2525 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2526
2527 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2528 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2529
2530 /* should we also check that parm and data areas do not overlap? */
790fe579 2531 if (*ppparm > end_of_smb) {
b6b38f70 2532 cFYI(1, "parms start after end of smb");
0a4b92c0 2533 return -EINVAL;
790fe579 2534 } else if (parm_count + *ppparm > end_of_smb) {
b6b38f70 2535 cFYI(1, "parm end after end of smb");
0a4b92c0 2536 return -EINVAL;
790fe579 2537 } else if (*ppdata > end_of_smb) {
b6b38f70 2538 cFYI(1, "data starts after end of smb");
0a4b92c0 2539 return -EINVAL;
790fe579 2540 } else if (data_count + *ppdata > end_of_smb) {
f19159dc 2541 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
50c2f753 2542 *ppdata, data_count, (data_count + *ppdata),
b6b38f70 2543 end_of_smb, pSMBr);
0a4b92c0 2544 return -EINVAL;
790fe579 2545 } else if (parm_count + data_count > pSMBr->ByteCount) {
b6b38f70 2546 cFYI(1, "parm count and data count larger than SMB");
0a4b92c0
SF
2547 return -EINVAL;
2548 }
630f3f0c
SF
2549 *pdatalen = data_count;
2550 *pparmlen = parm_count;
0a4b92c0
SF
2551 return 0;
2552}
2553
1da177e4
LT
2554int
2555CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2556 const unsigned char *searchName,
50c2f753 2557 char *symlinkinfo, const int buflen, __u16 fid,
1da177e4
LT
2558 const struct nls_table *nls_codepage)
2559{
2560 int rc = 0;
2561 int bytes_returned;
50c2f753
SF
2562 struct smb_com_transaction_ioctl_req *pSMB;
2563 struct smb_com_transaction_ioctl_rsp *pSMBr;
1da177e4 2564
b6b38f70 2565 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
1da177e4
LT
2566 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2567 (void **) &pSMBr);
2568 if (rc)
2569 return rc;
2570
2571 pSMB->TotalParameterCount = 0 ;
2572 pSMB->TotalDataCount = 0;
2573 pSMB->MaxParameterCount = cpu_to_le32(2);
2574 /* BB find exact data count max from sess structure BB */
0a4b92c0
SF
2575 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2576 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1da177e4
LT
2577 pSMB->MaxSetupCount = 4;
2578 pSMB->Reserved = 0;
2579 pSMB->ParameterOffset = 0;
2580 pSMB->DataCount = 0;
2581 pSMB->DataOffset = 0;
2582 pSMB->SetupCount = 4;
2583 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2584 pSMB->ParameterCount = pSMB->TotalParameterCount;
2585 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2586 pSMB->IsFsctl = 1; /* FSCTL */
2587 pSMB->IsRootFlag = 0;
2588 pSMB->Fid = fid; /* file handle always le */
2589 pSMB->ByteCount = 0;
2590
2591 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2592 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2593 if (rc) {
b6b38f70 2594 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
1da177e4
LT
2595 } else { /* decode response */
2596 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2597 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
afe48c31 2598 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
1da177e4
LT
2599 /* BB also check enough total bytes returned */
2600 rc = -EIO; /* bad smb */
afe48c31
SF
2601 goto qreparse_out;
2602 }
2603 if (data_count && (data_count < 2048)) {
2604 char *end_of_smb = 2 /* sizeof byte count */ +
2605 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1da177e4 2606
afe48c31 2607 struct reparse_data *reparse_buf =
50c2f753
SF
2608 (struct reparse_data *)
2609 ((char *)&pSMBr->hdr.Protocol
2610 + data_offset);
afe48c31
SF
2611 if ((char *)reparse_buf >= end_of_smb) {
2612 rc = -EIO;
2613 goto qreparse_out;
2614 }
2615 if ((reparse_buf->LinkNamesBuf +
2616 reparse_buf->TargetNameOffset +
2617 reparse_buf->TargetNameLen) > end_of_smb) {
b6b38f70 2618 cFYI(1, "reparse buf beyond SMB");
afe48c31
SF
2619 rc = -EIO;
2620 goto qreparse_out;
2621 }
50c2f753 2622
afe48c31
SF
2623 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2624 cifs_from_ucs2(symlinkinfo, (__le16 *)
50c2f753
SF
2625 (reparse_buf->LinkNamesBuf +
2626 reparse_buf->TargetNameOffset),
afe48c31
SF
2627 buflen,
2628 reparse_buf->TargetNameLen,
2629 nls_codepage, 0);
2630 } else { /* ASCII names */
2631 strncpy(symlinkinfo,
2632 reparse_buf->LinkNamesBuf +
2633 reparse_buf->TargetNameOffset,
2634 min_t(const int, buflen,
2635 reparse_buf->TargetNameLen));
1da177e4 2636 }
afe48c31
SF
2637 } else {
2638 rc = -EIO;
b6b38f70
JP
2639 cFYI(1, "Invalid return data count on "
2640 "get reparse info ioctl");
1da177e4 2641 }
afe48c31
SF
2642 symlinkinfo[buflen] = 0; /* just in case so the caller
2643 does not go off the end of the buffer */
b6b38f70 2644 cFYI(1, "readlink result - %s", symlinkinfo);
1da177e4 2645 }
989c7e51 2646
1da177e4 2647qreparse_out:
4a6d87f1 2648 cifs_buf_release(pSMB);
1da177e4
LT
2649
2650 /* Note: On -EAGAIN error only caller can retry on handle based calls
2651 since file handle passed in no longer valid */
2652
2653 return rc;
2654}
afe48c31 2655#endif /* CIFS_EXPERIMENTAL */
1da177e4
LT
2656
2657#ifdef CONFIG_CIFS_POSIX
2658
2659/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
50c2f753
SF
2660static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2661 struct cifs_posix_ace *cifs_ace)
1da177e4
LT
2662{
2663 /* u8 cifs fields do not need le conversion */
ff7feac9
SF
2664 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2665 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2666 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
b6b38f70 2667 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
1da177e4
LT
2668
2669 return;
2670}
2671
2672/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
50c2f753
SF
2673static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2674 const int acl_type, const int size_of_data_area)
1da177e4
LT
2675{
2676 int size = 0;
2677 int i;
2678 __u16 count;
50c2f753
SF
2679 struct cifs_posix_ace *pACE;
2680 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2681 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
1da177e4
LT
2682
2683 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2684 return -EOPNOTSUPP;
2685
790fe579 2686 if (acl_type & ACL_TYPE_ACCESS) {
1da177e4
LT
2687 count = le16_to_cpu(cifs_acl->access_entry_count);
2688 pACE = &cifs_acl->ace_array[0];
2689 size = sizeof(struct cifs_posix_acl);
2690 size += sizeof(struct cifs_posix_ace) * count;
2691 /* check if we would go beyond end of SMB */
790fe579 2692 if (size_of_data_area < size) {
b6b38f70
JP
2693 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2694 size_of_data_area, size);
1da177e4
LT
2695 return -EINVAL;
2696 }
790fe579 2697 } else if (acl_type & ACL_TYPE_DEFAULT) {
1da177e4
LT
2698 count = le16_to_cpu(cifs_acl->access_entry_count);
2699 size = sizeof(struct cifs_posix_acl);
2700 size += sizeof(struct cifs_posix_ace) * count;
2701/* skip past access ACEs to get to default ACEs */
2702 pACE = &cifs_acl->ace_array[count];
2703 count = le16_to_cpu(cifs_acl->default_entry_count);
2704 size += sizeof(struct cifs_posix_ace) * count;
2705 /* check if we would go beyond end of SMB */
790fe579 2706 if (size_of_data_area < size)
1da177e4
LT
2707 return -EINVAL;
2708 } else {
2709 /* illegal type */
2710 return -EINVAL;
2711 }
2712
2713 size = posix_acl_xattr_size(count);
790fe579 2714 if ((buflen == 0) || (local_acl == NULL)) {
50c2f753 2715 /* used to query ACL EA size */
790fe579 2716 } else if (size > buflen) {
1da177e4
LT
2717 return -ERANGE;
2718 } else /* buffer big enough */ {
ff7feac9 2719 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
50c2f753
SF
2720 for (i = 0; i < count ; i++) {
2721 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2722 pACE++;
1da177e4
LT
2723 }
2724 }
2725 return size;
2726}
2727
50c2f753
SF
2728static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2729 const posix_acl_xattr_entry *local_ace)
1da177e4
LT
2730{
2731 __u16 rc = 0; /* 0 = ACL converted ok */
2732
ff7feac9
SF
2733 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2734 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
1da177e4 2735 /* BB is there a better way to handle the large uid? */
790fe579 2736 if (local_ace->e_id == cpu_to_le32(-1)) {
1da177e4
LT
2737 /* Probably no need to le convert -1 on any arch but can not hurt */
2738 cifs_ace->cifs_uid = cpu_to_le64(-1);
50c2f753 2739 } else
ff7feac9 2740 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
b6b38f70 2741 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
1da177e4
LT
2742 return rc;
2743}
2744
2745/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
50c2f753
SF
2746static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2747 const int buflen, const int acl_type)
1da177e4
LT
2748{
2749 __u16 rc = 0;
50c2f753
SF
2750 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2751 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
1da177e4
LT
2752 int count;
2753 int i;
2754
790fe579 2755 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1da177e4
LT
2756 return 0;
2757
2758 count = posix_acl_xattr_count((size_t)buflen);
b6b38f70 2759 cFYI(1, "setting acl with %d entries from buf of length %d and "
63135e08 2760 "version of %d",
b6b38f70 2761 count, buflen, le32_to_cpu(local_acl->a_version));
790fe579 2762 if (le32_to_cpu(local_acl->a_version) != 2) {
b6b38f70
JP
2763 cFYI(1, "unknown POSIX ACL version %d",
2764 le32_to_cpu(local_acl->a_version));
1da177e4
LT
2765 return 0;
2766 }
2767 cifs_acl->version = cpu_to_le16(1);
790fe579 2768 if (acl_type == ACL_TYPE_ACCESS)
ff7feac9 2769 cifs_acl->access_entry_count = cpu_to_le16(count);
790fe579 2770 else if (acl_type == ACL_TYPE_DEFAULT)
ff7feac9 2771 cifs_acl->default_entry_count = cpu_to_le16(count);
1da177e4 2772 else {
b6b38f70 2773 cFYI(1, "unknown ACL type %d", acl_type);
1da177e4
LT
2774 return 0;
2775 }
50c2f753 2776 for (i = 0; i < count; i++) {
1da177e4
LT
2777 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2778 &local_acl->a_entries[i]);
790fe579 2779 if (rc != 0) {
1da177e4
LT
2780 /* ACE not converted */
2781 break;
2782 }
2783 }
790fe579 2784 if (rc == 0) {
1da177e4
LT
2785 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2786 rc += sizeof(struct cifs_posix_acl);
2787 /* BB add check to make sure ACL does not overflow SMB */
2788 }
2789 return rc;
2790}
2791
2792int
2793CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
50c2f753
SF
2794 const unsigned char *searchName,
2795 char *acl_inf, const int buflen, const int acl_type,
2796 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2797{
2798/* SMB_QUERY_POSIX_ACL */
2799 TRANSACTION2_QPI_REQ *pSMB = NULL;
2800 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2801 int rc = 0;
2802 int bytes_returned;
2803 int name_len;
2804 __u16 params, byte_count;
50c2f753 2805
b6b38f70 2806 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
1da177e4
LT
2807
2808queryAclRetry:
2809 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2810 (void **) &pSMBr);
2811 if (rc)
2812 return rc;
50c2f753 2813
1da177e4
LT
2814 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2815 name_len =
50c2f753 2816 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 2817 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2818 name_len++; /* trailing null */
2819 name_len *= 2;
2820 pSMB->FileName[name_len] = 0;
2821 pSMB->FileName[name_len+1] = 0;
50c2f753 2822 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2823 name_len = strnlen(searchName, PATH_MAX);
2824 name_len++; /* trailing null */
2825 strncpy(pSMB->FileName, searchName, name_len);
2826 }
2827
2828 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2829 pSMB->TotalDataCount = 0;
2830 pSMB->MaxParameterCount = cpu_to_le16(2);
50c2f753 2831 /* BB find exact max data count below from sess structure BB */
1da177e4
LT
2832 pSMB->MaxDataCount = cpu_to_le16(4000);
2833 pSMB->MaxSetupCount = 0;
2834 pSMB->Reserved = 0;
2835 pSMB->Flags = 0;
2836 pSMB->Timeout = 0;
2837 pSMB->Reserved2 = 0;
2838 pSMB->ParameterOffset = cpu_to_le16(
50c2f753
SF
2839 offsetof(struct smb_com_transaction2_qpi_req,
2840 InformationLevel) - 4);
1da177e4
LT
2841 pSMB->DataCount = 0;
2842 pSMB->DataOffset = 0;
2843 pSMB->SetupCount = 1;
2844 pSMB->Reserved3 = 0;
2845 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2846 byte_count = params + 1 /* pad */ ;
2847 pSMB->TotalParameterCount = cpu_to_le16(params);
2848 pSMB->ParameterCount = pSMB->TotalParameterCount;
2849 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2850 pSMB->Reserved4 = 0;
2851 pSMB->hdr.smb_buf_length += byte_count;
2852 pSMB->ByteCount = cpu_to_le16(byte_count);
2853
2854 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2855 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
0a4b92c0 2856 cifs_stats_inc(&tcon->num_acl_get);
1da177e4 2857 if (rc) {
b6b38f70 2858 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
1da177e4
LT
2859 } else {
2860 /* decode response */
50c2f753 2861
1da177e4
LT
2862 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2863 if (rc || (pSMBr->ByteCount < 2))
2864 /* BB also check enough total bytes returned */
2865 rc = -EIO; /* bad smb */
2866 else {
2867 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2868 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2869 rc = cifs_copy_posix_acl(acl_inf,
2870 (char *)&pSMBr->hdr.Protocol+data_offset,
50c2f753 2871 buflen, acl_type, count);
1da177e4
LT
2872 }
2873 }
2874 cifs_buf_release(pSMB);
2875 if (rc == -EAGAIN)
2876 goto queryAclRetry;
2877 return rc;
2878}
2879
2880int
2881CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
50c2f753
SF
2882 const unsigned char *fileName,
2883 const char *local_acl, const int buflen,
2884 const int acl_type,
2885 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2886{
2887 struct smb_com_transaction2_spi_req *pSMB = NULL;
2888 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2889 char *parm_data;
2890 int name_len;
2891 int rc = 0;
2892 int bytes_returned = 0;
2893 __u16 params, byte_count, data_count, param_offset, offset;
2894
b6b38f70 2895 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
1da177e4
LT
2896setAclRetry:
2897 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 2898 (void **) &pSMBr);
1da177e4
LT
2899 if (rc)
2900 return rc;
2901 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2902 name_len =
50c2f753 2903 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 2904 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2905 name_len++; /* trailing null */
2906 name_len *= 2;
50c2f753 2907 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2908 name_len = strnlen(fileName, PATH_MAX);
2909 name_len++; /* trailing null */
2910 strncpy(pSMB->FileName, fileName, name_len);
2911 }
2912 params = 6 + name_len;
2913 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
2914 /* BB find max SMB size from sess */
2915 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
2916 pSMB->MaxSetupCount = 0;
2917 pSMB->Reserved = 0;
2918 pSMB->Flags = 0;
2919 pSMB->Timeout = 0;
2920 pSMB->Reserved2 = 0;
2921 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2922 InformationLevel) - 4;
1da177e4
LT
2923 offset = param_offset + params;
2924 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2925 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2926
2927 /* convert to on the wire format for POSIX ACL */
50c2f753 2928 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
1da177e4 2929
790fe579 2930 if (data_count == 0) {
1da177e4
LT
2931 rc = -EOPNOTSUPP;
2932 goto setACLerrorExit;
2933 }
2934 pSMB->DataOffset = cpu_to_le16(offset);
2935 pSMB->SetupCount = 1;
2936 pSMB->Reserved3 = 0;
2937 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2938 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2939 byte_count = 3 /* pad */ + params + data_count;
2940 pSMB->DataCount = cpu_to_le16(data_count);
2941 pSMB->TotalDataCount = pSMB->DataCount;
2942 pSMB->ParameterCount = cpu_to_le16(params);
2943 pSMB->TotalParameterCount = pSMB->ParameterCount;
2944 pSMB->Reserved4 = 0;
2945 pSMB->hdr.smb_buf_length += byte_count;
2946 pSMB->ByteCount = cpu_to_le16(byte_count);
2947 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 2948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 2949 if (rc)
b6b38f70 2950 cFYI(1, "Set POSIX ACL returned %d", rc);
1da177e4
LT
2951
2952setACLerrorExit:
2953 cifs_buf_release(pSMB);
2954 if (rc == -EAGAIN)
2955 goto setAclRetry;
2956 return rc;
2957}
2958
f654bac2
SF
2959/* BB fix tabs in this function FIXME BB */
2960int
2961CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
ad7a2926 2962 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
f654bac2 2963{
50c2f753
SF
2964 int rc = 0;
2965 struct smb_t2_qfi_req *pSMB = NULL;
2966 struct smb_t2_qfi_rsp *pSMBr = NULL;
2967 int bytes_returned;
2968 __u16 params, byte_count;
f654bac2 2969
b6b38f70 2970 cFYI(1, "In GetExtAttr");
790fe579
SF
2971 if (tcon == NULL)
2972 return -ENODEV;
f654bac2
SF
2973
2974GetExtAttrRetry:
790fe579
SF
2975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2976 (void **) &pSMBr);
2977 if (rc)
2978 return rc;
f654bac2 2979
ad7a2926 2980 params = 2 /* level */ + 2 /* fid */;
790fe579
SF
2981 pSMB->t2.TotalDataCount = 0;
2982 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2983 /* BB find exact max data count below from sess structure BB */
2984 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2985 pSMB->t2.MaxSetupCount = 0;
2986 pSMB->t2.Reserved = 0;
2987 pSMB->t2.Flags = 0;
2988 pSMB->t2.Timeout = 0;
2989 pSMB->t2.Reserved2 = 0;
2990 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2991 Fid) - 4);
2992 pSMB->t2.DataCount = 0;
2993 pSMB->t2.DataOffset = 0;
2994 pSMB->t2.SetupCount = 1;
2995 pSMB->t2.Reserved3 = 0;
2996 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2997 byte_count = params + 1 /* pad */ ;
2998 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2999 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3000 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3001 pSMB->Pad = 0;
f654bac2 3002 pSMB->Fid = netfid;
790fe579
SF
3003 pSMB->hdr.smb_buf_length += byte_count;
3004 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3005
3006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3008 if (rc) {
b6b38f70 3009 cFYI(1, "error %d in GetExtAttr", rc);
790fe579
SF
3010 } else {
3011 /* decode response */
3012 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3013 if (rc || (pSMBr->ByteCount < 2))
3014 /* BB also check enough total bytes returned */
3015 /* If rc should we check for EOPNOSUPP and
3016 disable the srvino flag? or in caller? */
3017 rc = -EIO; /* bad smb */
3018 else {
3019 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3020 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3021 struct file_chattr_info *pfinfo;
3022 /* BB Do we need a cast or hash here ? */
3023 if (count != 16) {
b6b38f70 3024 cFYI(1, "Illegal size ret in GetExtAttr");
790fe579
SF
3025 rc = -EIO;
3026 goto GetExtAttrOut;
3027 }
3028 pfinfo = (struct file_chattr_info *)
3029 (data_offset + (char *) &pSMBr->hdr.Protocol);
3030 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
f654bac2 3031 *pMask = le64_to_cpu(pfinfo->mask);
790fe579
SF
3032 }
3033 }
f654bac2 3034GetExtAttrOut:
790fe579
SF
3035 cifs_buf_release(pSMB);
3036 if (rc == -EAGAIN)
3037 goto GetExtAttrRetry;
3038 return rc;
f654bac2
SF
3039}
3040
f654bac2 3041#endif /* CONFIG_POSIX */
1da177e4 3042
297647c2 3043#ifdef CONFIG_CIFS_EXPERIMENTAL
0a4b92c0
SF
3044/* Get Security Descriptor (by handle) from remote server for a file or dir */
3045int
3046CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
630f3f0c 3047 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
0a4b92c0
SF
3048{
3049 int rc = 0;
3050 int buf_type = 0;
ad7a2926 3051 QUERY_SEC_DESC_REQ *pSMB;
0a4b92c0
SF
3052 struct kvec iov[1];
3053
b6b38f70 3054 cFYI(1, "GetCifsACL");
0a4b92c0 3055
630f3f0c
SF
3056 *pbuflen = 0;
3057 *acl_inf = NULL;
3058
b9c7a2bb 3059 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
0a4b92c0
SF
3060 8 /* parm len */, tcon, (void **) &pSMB);
3061 if (rc)
3062 return rc;
3063
3064 pSMB->MaxParameterCount = cpu_to_le32(4);
3065 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3066 pSMB->MaxSetupCount = 0;
3067 pSMB->Fid = fid; /* file handle always le */
3068 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3069 CIFS_ACL_DACL);
3070 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3071 pSMB->hdr.smb_buf_length += 11;
3072 iov[0].iov_base = (char *)pSMB;
3073 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3074
a761ac57 3075 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
133672ef 3076 CIFS_STD_OP);
0a4b92c0
SF
3077 cifs_stats_inc(&tcon->num_acl_get);
3078 if (rc) {
b6b38f70 3079 cFYI(1, "Send error in QuerySecDesc = %d", rc);
0a4b92c0 3080 } else { /* decode response */
ad7a2926 3081 __le32 *parm;
630f3f0c
SF
3082 __u32 parm_len;
3083 __u32 acl_len;
50c2f753 3084 struct smb_com_ntransact_rsp *pSMBr;
630f3f0c 3085 char *pdata;
0a4b92c0
SF
3086
3087/* validate_nttransact */
50c2f753 3088 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
630f3f0c 3089 &pdata, &parm_len, pbuflen);
790fe579 3090 if (rc)
0a4b92c0
SF
3091 goto qsec_out;
3092 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3093
b6b38f70 3094 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
0a4b92c0
SF
3095
3096 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3097 rc = -EIO; /* bad smb */
630f3f0c 3098 *pbuflen = 0;
0a4b92c0
SF
3099 goto qsec_out;
3100 }
3101
3102/* BB check that data area is minimum length and as big as acl_len */
3103
af6f4612 3104 acl_len = le32_to_cpu(*parm);
630f3f0c 3105 if (acl_len != *pbuflen) {
b6b38f70
JP
3106 cERROR(1, "acl length %d does not match %d",
3107 acl_len, *pbuflen);
630f3f0c
SF
3108 if (*pbuflen > acl_len)
3109 *pbuflen = acl_len;
3110 }
0a4b92c0 3111
630f3f0c
SF
3112 /* check if buffer is big enough for the acl
3113 header followed by the smallest SID */
3114 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3115 (*pbuflen >= 64 * 1024)) {
b6b38f70 3116 cERROR(1, "bad acl length %d", *pbuflen);
630f3f0c
SF
3117 rc = -EINVAL;
3118 *pbuflen = 0;
3119 } else {
3120 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3121 if (*acl_inf == NULL) {
3122 *pbuflen = 0;
3123 rc = -ENOMEM;
3124 }
3125 memcpy(*acl_inf, pdata, *pbuflen);
3126 }
0a4b92c0
SF
3127 }
3128qsec_out:
790fe579 3129 if (buf_type == CIFS_SMALL_BUFFER)
0a4b92c0 3130 cifs_small_buf_release(iov[0].iov_base);
790fe579 3131 else if (buf_type == CIFS_LARGE_BUFFER)
0a4b92c0 3132 cifs_buf_release(iov[0].iov_base);
4b8f930f 3133/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
0a4b92c0
SF
3134 return rc;
3135}
97837582
SF
3136
3137int
3138CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3139 struct cifs_ntsd *pntsd, __u32 acllen)
3140{
3141 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3142 int rc = 0;
3143 int bytes_returned = 0;
3144 SET_SEC_DESC_REQ *pSMB = NULL;
3145 NTRANSACT_RSP *pSMBr = NULL;
3146
3147setCifsAclRetry:
3148 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3149 (void **) &pSMBr);
3150 if (rc)
3151 return (rc);
3152
3153 pSMB->MaxSetupCount = 0;
3154 pSMB->Reserved = 0;
3155
3156 param_count = 8;
3157 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3158 data_count = acllen;
3159 data_offset = param_offset + param_count;
3160 byte_count = 3 /* pad */ + param_count;
3161
3162 pSMB->DataCount = cpu_to_le32(data_count);
3163 pSMB->TotalDataCount = pSMB->DataCount;
3164 pSMB->MaxParameterCount = cpu_to_le32(4);
3165 pSMB->MaxDataCount = cpu_to_le32(16384);
3166 pSMB->ParameterCount = cpu_to_le32(param_count);
3167 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3168 pSMB->TotalParameterCount = pSMB->ParameterCount;
3169 pSMB->DataOffset = cpu_to_le32(data_offset);
3170 pSMB->SetupCount = 0;
3171 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3172 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3173
3174 pSMB->Fid = fid; /* file handle always le */
3175 pSMB->Reserved2 = 0;
3176 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3177
3178 if (pntsd && acllen) {
3179 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3180 (char *) pntsd,
3181 acllen);
3182 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3183
3184 } else
3185 pSMB->hdr.smb_buf_length += byte_count;
3186
3187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3189
b6b38f70 3190 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
97837582 3191 if (rc)
b6b38f70 3192 cFYI(1, "Set CIFS ACL returned %d", rc);
97837582
SF
3193 cifs_buf_release(pSMB);
3194
3195 if (rc == -EAGAIN)
3196 goto setCifsAclRetry;
3197
3198 return (rc);
3199}
3200
297647c2 3201#endif /* CONFIG_CIFS_EXPERIMENTAL */
0a4b92c0 3202
6b8edfe0
SF
3203/* Legacy Query Path Information call for lookup to old servers such
3204 as Win9x/WinME */
3205int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
50c2f753
SF
3206 const unsigned char *searchName,
3207 FILE_ALL_INFO *pFinfo,
3208 const struct nls_table *nls_codepage, int remap)
6b8edfe0 3209{
ad7a2926
SF
3210 QUERY_INFORMATION_REQ *pSMB;
3211 QUERY_INFORMATION_RSP *pSMBr;
6b8edfe0
SF
3212 int rc = 0;
3213 int bytes_returned;
3214 int name_len;
3215
b6b38f70 3216 cFYI(1, "In SMBQPath path %s", searchName);
6b8edfe0
SF
3217QInfRetry:
3218 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
50c2f753 3219 (void **) &pSMBr);
6b8edfe0
SF
3220 if (rc)
3221 return rc;
3222
3223 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3224 name_len =
50c2f753
SF
3225 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3226 PATH_MAX, nls_codepage, remap);
6b8edfe0
SF
3227 name_len++; /* trailing null */
3228 name_len *= 2;
50c2f753 3229 } else {
6b8edfe0
SF
3230 name_len = strnlen(searchName, PATH_MAX);
3231 name_len++; /* trailing null */
3232 strncpy(pSMB->FileName, searchName, name_len);
3233 }
3234 pSMB->BufferFormat = 0x04;
50c2f753 3235 name_len++; /* account for buffer type byte */
6b8edfe0
SF
3236 pSMB->hdr.smb_buf_length += (__u16) name_len;
3237 pSMB->ByteCount = cpu_to_le16(name_len);
3238
3239 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 3240 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6b8edfe0 3241 if (rc) {
b6b38f70 3242 cFYI(1, "Send error in QueryInfo = %d", rc);
ad7a2926 3243 } else if (pFinfo) {
1bd5bbcb
SF
3244 struct timespec ts;
3245 __u32 time = le32_to_cpu(pSMBr->last_write_time);
ad7a2926
SF
3246
3247 /* decode response */
1bd5bbcb 3248 /* BB FIXME - add time zone adjustment BB */
6b8edfe0 3249 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
1bd5bbcb
SF
3250 ts.tv_nsec = 0;
3251 ts.tv_sec = time;
3252 /* decode time fields */
733f99ac 3253 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
1bd5bbcb
SF
3254 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3255 pFinfo->LastAccessTime = 0;
70ca734a
SF
3256 pFinfo->AllocationSize =
3257 cpu_to_le64(le32_to_cpu(pSMBr->size));
3258 pFinfo->EndOfFile = pFinfo->AllocationSize;
3259 pFinfo->Attributes =
3260 cpu_to_le32(le16_to_cpu(pSMBr->attr));
6b8edfe0
SF
3261 } else
3262 rc = -EIO; /* bad buffer passed in */
3263
3264 cifs_buf_release(pSMB);
3265
3266 if (rc == -EAGAIN)
3267 goto QInfRetry;
3268
3269 return rc;
3270}
3271
bcd5357f
JL
3272int
3273CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3274 u16 netfid, FILE_ALL_INFO *pFindData)
3275{
3276 struct smb_t2_qfi_req *pSMB = NULL;
3277 struct smb_t2_qfi_rsp *pSMBr = NULL;
3278 int rc = 0;
3279 int bytes_returned;
3280 __u16 params, byte_count;
3281
3282QFileInfoRetry:
3283 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3284 (void **) &pSMBr);
3285 if (rc)
3286 return rc;
3287
3288 params = 2 /* level */ + 2 /* fid */;
3289 pSMB->t2.TotalDataCount = 0;
3290 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3291 /* BB find exact max data count below from sess structure BB */
3292 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3293 pSMB->t2.MaxSetupCount = 0;
3294 pSMB->t2.Reserved = 0;
3295 pSMB->t2.Flags = 0;
3296 pSMB->t2.Timeout = 0;
3297 pSMB->t2.Reserved2 = 0;
3298 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3299 Fid) - 4);
3300 pSMB->t2.DataCount = 0;
3301 pSMB->t2.DataOffset = 0;
3302 pSMB->t2.SetupCount = 1;
3303 pSMB->t2.Reserved3 = 0;
3304 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3305 byte_count = params + 1 /* pad */ ;
3306 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3307 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3308 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3309 pSMB->Pad = 0;
3310 pSMB->Fid = netfid;
3311 pSMB->hdr.smb_buf_length += byte_count;
6b8edfe0 3312
bcd5357f
JL
3313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3314 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3315 if (rc) {
f19159dc 3316 cFYI(1, "Send error in QPathInfo = %d", rc);
bcd5357f
JL
3317 } else { /* decode response */
3318 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6b8edfe0 3319
bcd5357f
JL
3320 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3321 rc = -EIO;
3322 else if (pSMBr->ByteCount < 40)
3323 rc = -EIO; /* bad smb */
3324 else if (pFindData) {
3325 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3326 memcpy((char *) pFindData,
3327 (char *) &pSMBr->hdr.Protocol +
3328 data_offset, sizeof(FILE_ALL_INFO));
3329 } else
3330 rc = -ENOMEM;
3331 }
3332 cifs_buf_release(pSMB);
3333 if (rc == -EAGAIN)
3334 goto QFileInfoRetry;
6b8edfe0 3335
bcd5357f
JL
3336 return rc;
3337}
6b8edfe0 3338
1da177e4
LT
3339int
3340CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3341 const unsigned char *searchName,
ad7a2926 3342 FILE_ALL_INFO *pFindData,
acf1a1b1 3343 int legacy /* old style infolevel */,
737b758c 3344 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3345{
3346/* level 263 SMB_QUERY_FILE_ALL_INFO */
3347 TRANSACTION2_QPI_REQ *pSMB = NULL;
3348 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3349 int rc = 0;
3350 int bytes_returned;
3351 int name_len;
3352 __u16 params, byte_count;
3353
b6b38f70 3354/* cFYI(1, "In QPathInfo path %s", searchName); */
1da177e4
LT
3355QPathInfoRetry:
3356 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3357 (void **) &pSMBr);
3358 if (rc)
3359 return rc;
3360
3361 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3362 name_len =
50c2f753 3363 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 3364 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3365 name_len++; /* trailing null */
3366 name_len *= 2;
50c2f753 3367 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3368 name_len = strnlen(searchName, PATH_MAX);
3369 name_len++; /* trailing null */
3370 strncpy(pSMB->FileName, searchName, name_len);
3371 }
3372
50c2f753 3373 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
3374 pSMB->TotalDataCount = 0;
3375 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
3376 /* BB find exact max SMB PDU from sess structure BB */
3377 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
3378 pSMB->MaxSetupCount = 0;
3379 pSMB->Reserved = 0;
3380 pSMB->Flags = 0;
3381 pSMB->Timeout = 0;
3382 pSMB->Reserved2 = 0;
3383 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3384 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3385 pSMB->DataCount = 0;
3386 pSMB->DataOffset = 0;
3387 pSMB->SetupCount = 1;
3388 pSMB->Reserved3 = 0;
3389 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3390 byte_count = params + 1 /* pad */ ;
3391 pSMB->TotalParameterCount = cpu_to_le16(params);
3392 pSMB->ParameterCount = pSMB->TotalParameterCount;
790fe579 3393 if (legacy)
acf1a1b1
SF
3394 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3395 else
3396 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
1da177e4
LT
3397 pSMB->Reserved4 = 0;
3398 pSMB->hdr.smb_buf_length += byte_count;
3399 pSMB->ByteCount = cpu_to_le16(byte_count);
3400
3401 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3403 if (rc) {
b6b38f70 3404 cFYI(1, "Send error in QPathInfo = %d", rc);
1da177e4
LT
3405 } else { /* decode response */
3406 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3407
acf1a1b1
SF
3408 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3409 rc = -EIO;
50c2f753 3410 else if (!legacy && (pSMBr->ByteCount < 40))
1da177e4 3411 rc = -EIO; /* bad smb */
790fe579 3412 else if (legacy && (pSMBr->ByteCount < 24))
50c2f753
SF
3413 rc = -EIO; /* 24 or 26 expected but we do not read
3414 last field */
3415 else if (pFindData) {
acf1a1b1 3416 int size;
1da177e4 3417 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
ad7a2926
SF
3418
3419 /* On legacy responses we do not read the last field,
3420 EAsize, fortunately since it varies by subdialect and
3421 also note it differs on Set vs. Get, ie two bytes or 4
3422 bytes depending but we don't care here */
3423 if (legacy)
acf1a1b1
SF
3424 size = sizeof(FILE_INFO_STANDARD);
3425 else
3426 size = sizeof(FILE_ALL_INFO);
1da177e4
LT
3427 memcpy((char *) pFindData,
3428 (char *) &pSMBr->hdr.Protocol +
acf1a1b1 3429 data_offset, size);
1da177e4
LT
3430 } else
3431 rc = -ENOMEM;
3432 }
3433 cifs_buf_release(pSMB);
3434 if (rc == -EAGAIN)
3435 goto QPathInfoRetry;
3436
3437 return rc;
3438}
3439
c8634fd3
JL
3440int
3441CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3442 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3443{
3444 struct smb_t2_qfi_req *pSMB = NULL;
3445 struct smb_t2_qfi_rsp *pSMBr = NULL;
3446 int rc = 0;
3447 int bytes_returned;
3448 __u16 params, byte_count;
3449
3450UnixQFileInfoRetry:
3451 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3452 (void **) &pSMBr);
3453 if (rc)
3454 return rc;
3455
3456 params = 2 /* level */ + 2 /* fid */;
3457 pSMB->t2.TotalDataCount = 0;
3458 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3459 /* BB find exact max data count below from sess structure BB */
3460 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3461 pSMB->t2.MaxSetupCount = 0;
3462 pSMB->t2.Reserved = 0;
3463 pSMB->t2.Flags = 0;
3464 pSMB->t2.Timeout = 0;
3465 pSMB->t2.Reserved2 = 0;
3466 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3467 Fid) - 4);
3468 pSMB->t2.DataCount = 0;
3469 pSMB->t2.DataOffset = 0;
3470 pSMB->t2.SetupCount = 1;
3471 pSMB->t2.Reserved3 = 0;
3472 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3473 byte_count = params + 1 /* pad */ ;
3474 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3475 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3476 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3477 pSMB->Pad = 0;
3478 pSMB->Fid = netfid;
3479 pSMB->hdr.smb_buf_length += byte_count;
3480
3481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3482 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3483 if (rc) {
f19159dc 3484 cFYI(1, "Send error in QPathInfo = %d", rc);
c8634fd3
JL
3485 } else { /* decode response */
3486 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3487
3488 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
f19159dc 3489 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
c8634fd3 3490 "Unix Extensions can be disabled on mount "
f19159dc 3491 "by specifying the nosfu mount option.");
c8634fd3
JL
3492 rc = -EIO; /* bad smb */
3493 } else {
3494 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3495 memcpy((char *) pFindData,
3496 (char *) &pSMBr->hdr.Protocol +
3497 data_offset,
3498 sizeof(FILE_UNIX_BASIC_INFO));
3499 }
3500 }
3501
3502 cifs_buf_release(pSMB);
3503 if (rc == -EAGAIN)
3504 goto UnixQFileInfoRetry;
3505
3506 return rc;
3507}
3508
1da177e4
LT
3509int
3510CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3511 const unsigned char *searchName,
582d21e5 3512 FILE_UNIX_BASIC_INFO *pFindData,
737b758c 3513 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3514{
3515/* SMB_QUERY_FILE_UNIX_BASIC */
3516 TRANSACTION2_QPI_REQ *pSMB = NULL;
3517 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3518 int rc = 0;
3519 int bytes_returned = 0;
3520 int name_len;
3521 __u16 params, byte_count;
3522
b6b38f70 3523 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
1da177e4
LT
3524UnixQPathInfoRetry:
3525 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3526 (void **) &pSMBr);
3527 if (rc)
3528 return rc;
3529
3530 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3531 name_len =
b1a45695 3532 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 3533 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3534 name_len++; /* trailing null */
3535 name_len *= 2;
50c2f753 3536 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3537 name_len = strnlen(searchName, PATH_MAX);
3538 name_len++; /* trailing null */
3539 strncpy(pSMB->FileName, searchName, name_len);
3540 }
3541
50c2f753 3542 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
3543 pSMB->TotalDataCount = 0;
3544 pSMB->MaxParameterCount = cpu_to_le16(2);
3545 /* BB find exact max SMB PDU from sess structure BB */
50c2f753 3546 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
3547 pSMB->MaxSetupCount = 0;
3548 pSMB->Reserved = 0;
3549 pSMB->Flags = 0;
3550 pSMB->Timeout = 0;
3551 pSMB->Reserved2 = 0;
3552 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3553 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3554 pSMB->DataCount = 0;
3555 pSMB->DataOffset = 0;
3556 pSMB->SetupCount = 1;
3557 pSMB->Reserved3 = 0;
3558 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3559 byte_count = params + 1 /* pad */ ;
3560 pSMB->TotalParameterCount = cpu_to_le16(params);
3561 pSMB->ParameterCount = pSMB->TotalParameterCount;
3562 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3563 pSMB->Reserved4 = 0;
3564 pSMB->hdr.smb_buf_length += byte_count;
3565 pSMB->ByteCount = cpu_to_le16(byte_count);
3566
3567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3569 if (rc) {
b6b38f70 3570 cFYI(1, "Send error in QPathInfo = %d", rc);
1da177e4
LT
3571 } else { /* decode response */
3572 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3573
3574 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
b6b38f70 3575 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
1e71f25d 3576 "Unix Extensions can be disabled on mount "
b6b38f70 3577 "by specifying the nosfu mount option.");
1da177e4
LT
3578 rc = -EIO; /* bad smb */
3579 } else {
3580 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3581 memcpy((char *) pFindData,
3582 (char *) &pSMBr->hdr.Protocol +
3583 data_offset,
630f3f0c 3584 sizeof(FILE_UNIX_BASIC_INFO));
1da177e4
LT
3585 }
3586 }
3587 cifs_buf_release(pSMB);
3588 if (rc == -EAGAIN)
3589 goto UnixQPathInfoRetry;
3590
3591 return rc;
3592}
3593
1da177e4
LT
3594/* xid, tcon, searchName and codepage are input parms, rest are returned */
3595int
3596CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
50c2f753 3597 const char *searchName,
1da177e4 3598 const struct nls_table *nls_codepage,
50c2f753
SF
3599 __u16 *pnetfid,
3600 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
1da177e4
LT
3601{
3602/* level 257 SMB_ */
3603 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3604 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
ad7a2926 3605 T2_FFIRST_RSP_PARMS *parms;
1da177e4
LT
3606 int rc = 0;
3607 int bytes_returned = 0;
3608 int name_len;
3609 __u16 params, byte_count;
3610
b6b38f70 3611 cFYI(1, "In FindFirst for %s", searchName);
1da177e4
LT
3612
3613findFirstRetry:
3614 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3615 (void **) &pSMBr);
3616 if (rc)
3617 return rc;
3618
3619 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3620 name_len =
50c2f753 3621 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c
SF
3622 PATH_MAX, nls_codepage, remap);
3623 /* We can not add the asterik earlier in case
3624 it got remapped to 0xF03A as if it were part of the
3625 directory name instead of a wildcard */
1da177e4 3626 name_len *= 2;
ac67055e 3627 pSMB->FileName[name_len] = dirsep;
737b758c
SF
3628 pSMB->FileName[name_len+1] = 0;
3629 pSMB->FileName[name_len+2] = '*';
3630 pSMB->FileName[name_len+3] = 0;
3631 name_len += 4; /* now the trailing null */
1da177e4
LT
3632 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3633 pSMB->FileName[name_len+1] = 0;
737b758c 3634 name_len += 2;
1da177e4
LT
3635 } else { /* BB add check for overrun of SMB buf BB */
3636 name_len = strnlen(searchName, PATH_MAX);
1da177e4 3637/* BB fix here and in unicode clause above ie
790fe579 3638 if (name_len > buffersize-header)
1da177e4
LT
3639 free buffer exit; BB */
3640 strncpy(pSMB->FileName, searchName, name_len);
ac67055e 3641 pSMB->FileName[name_len] = dirsep;
68575476
SF
3642 pSMB->FileName[name_len+1] = '*';
3643 pSMB->FileName[name_len+2] = 0;
3644 name_len += 3;
1da177e4
LT
3645 }
3646
3647 params = 12 + name_len /* includes null */ ;
3648 pSMB->TotalDataCount = 0; /* no EAs */
3649 pSMB->MaxParameterCount = cpu_to_le16(10);
3650 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3651 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3652 pSMB->MaxSetupCount = 0;
3653 pSMB->Reserved = 0;
3654 pSMB->Flags = 0;
3655 pSMB->Timeout = 0;
3656 pSMB->Reserved2 = 0;
3657 byte_count = params + 1 /* pad */ ;
3658 pSMB->TotalParameterCount = cpu_to_le16(params);
3659 pSMB->ParameterCount = pSMB->TotalParameterCount;
3660 pSMB->ParameterOffset = cpu_to_le16(
88274815
SF
3661 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3662 - 4);
1da177e4
LT
3663 pSMB->DataCount = 0;
3664 pSMB->DataOffset = 0;
3665 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3666 pSMB->Reserved3 = 0;
3667 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3668 pSMB->SearchAttributes =
3669 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3670 ATTR_DIRECTORY);
50c2f753
SF
3671 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3672 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
1da177e4
LT
3673 CIFS_SEARCH_RETURN_RESUME);
3674 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3675
3676 /* BB what should we set StorageType to? Does it matter? BB */
3677 pSMB->SearchStorageType = 0;
3678 pSMB->hdr.smb_buf_length += byte_count;
3679 pSMB->ByteCount = cpu_to_le16(byte_count);
3680
3681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3683 cifs_stats_inc(&tcon->num_ffirst);
1da177e4 3684
88274815
SF
3685 if (rc) {/* BB add logic to retry regular search if Unix search
3686 rejected unexpectedly by server */
1da177e4 3687 /* BB Add code to handle unsupported level rc */
b6b38f70 3688 cFYI(1, "Error in FindFirst = %d", rc);
1982c344 3689
88274815 3690 cifs_buf_release(pSMB);
1da177e4
LT
3691
3692 /* BB eventually could optimize out free and realloc of buf */
3693 /* for this case */
3694 if (rc == -EAGAIN)
3695 goto findFirstRetry;
3696 } else { /* decode response */
3697 /* BB remember to free buffer if error BB */
3698 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
790fe579 3699 if (rc == 0) {
b77d753c
SF
3700 unsigned int lnoff;
3701
1da177e4 3702 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 3703 psrch_inf->unicode = true;
1da177e4 3704 else
4b18f2a9 3705 psrch_inf->unicode = false;
1da177e4
LT
3706
3707 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
d47d7c1a 3708 psrch_inf->smallBuf = 0;
50c2f753
SF
3709 psrch_inf->srch_entries_start =
3710 (char *) &pSMBr->hdr.Protocol +
1da177e4 3711 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
3712 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3713 le16_to_cpu(pSMBr->t2.ParameterOffset));
3714
790fe579 3715 if (parms->EndofSearch)
4b18f2a9 3716 psrch_inf->endOfSearch = true;
1da177e4 3717 else
4b18f2a9 3718 psrch_inf->endOfSearch = false;
1da177e4 3719
50c2f753
SF
3720 psrch_inf->entries_in_buffer =
3721 le16_to_cpu(parms->SearchCount);
60808233 3722 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
1da177e4 3723 psrch_inf->entries_in_buffer;
b77d753c
SF
3724 lnoff = le16_to_cpu(parms->LastNameOffset);
3725 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3726 lnoff) {
b6b38f70 3727 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
3728 psrch_inf->last_entry = NULL;
3729 return rc;
3730 }
3731
0752f152 3732 psrch_inf->last_entry = psrch_inf->srch_entries_start +
b77d753c
SF
3733 lnoff;
3734
1da177e4
LT
3735 *pnetfid = parms->SearchHandle;
3736 } else {
3737 cifs_buf_release(pSMB);
3738 }
3739 }
3740
3741 return rc;
3742}
3743
3744int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
50c2f753 3745 __u16 searchHandle, struct cifs_search_info *psrch_inf)
1da177e4
LT
3746{
3747 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3748 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
ad7a2926 3749 T2_FNEXT_RSP_PARMS *parms;
1da177e4
LT
3750 char *response_data;
3751 int rc = 0;
3752 int bytes_returned, name_len;
3753 __u16 params, byte_count;
3754
b6b38f70 3755 cFYI(1, "In FindNext");
1da177e4 3756
4b18f2a9 3757 if (psrch_inf->endOfSearch)
1da177e4
LT
3758 return -ENOENT;
3759
3760 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3761 (void **) &pSMBr);
3762 if (rc)
3763 return rc;
3764
50c2f753 3765 params = 14; /* includes 2 bytes of null string, converted to LE below*/
1da177e4
LT
3766 byte_count = 0;
3767 pSMB->TotalDataCount = 0; /* no EAs */
3768 pSMB->MaxParameterCount = cpu_to_le16(8);
3769 pSMB->MaxDataCount =
50c2f753
SF
3770 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3771 0xFFFFFF00);
1da177e4
LT
3772 pSMB->MaxSetupCount = 0;
3773 pSMB->Reserved = 0;
3774 pSMB->Flags = 0;
3775 pSMB->Timeout = 0;
3776 pSMB->Reserved2 = 0;
3777 pSMB->ParameterOffset = cpu_to_le16(
3778 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3779 pSMB->DataCount = 0;
3780 pSMB->DataOffset = 0;
3781 pSMB->SetupCount = 1;
3782 pSMB->Reserved3 = 0;
3783 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3784 pSMB->SearchHandle = searchHandle; /* always kept as le */
3785 pSMB->SearchCount =
630f3f0c 3786 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
1da177e4
LT
3787 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3788 pSMB->ResumeKey = psrch_inf->resume_key;
3789 pSMB->SearchFlags =
3790 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3791
3792 name_len = psrch_inf->resume_name_len;
3793 params += name_len;
790fe579 3794 if (name_len < PATH_MAX) {
1da177e4
LT
3795 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3796 byte_count += name_len;
ef6724e3
SF
3797 /* 14 byte parm len above enough for 2 byte null terminator */
3798 pSMB->ResumeFileName[name_len] = 0;
3799 pSMB->ResumeFileName[name_len+1] = 0;
1da177e4
LT
3800 } else {
3801 rc = -EINVAL;
3802 goto FNext2_err_exit;
3803 }
3804 byte_count = params + 1 /* pad */ ;
3805 pSMB->TotalParameterCount = cpu_to_le16(params);
3806 pSMB->ParameterCount = pSMB->TotalParameterCount;
3807 pSMB->hdr.smb_buf_length += byte_count;
3808 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 3809
1da177e4
LT
3810 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3812 cifs_stats_inc(&tcon->num_fnext);
1da177e4
LT
3813 if (rc) {
3814 if (rc == -EBADF) {
4b18f2a9 3815 psrch_inf->endOfSearch = true;
6353450a 3816 cifs_buf_release(pSMB);
50c2f753 3817 rc = 0; /* search probably was closed at end of search*/
1da177e4 3818 } else
b6b38f70 3819 cFYI(1, "FindNext returned = %d", rc);
1da177e4
LT
3820 } else { /* decode response */
3821 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50c2f753 3822
790fe579 3823 if (rc == 0) {
b77d753c
SF
3824 unsigned int lnoff;
3825
1da177e4
LT
3826 /* BB fixme add lock for file (srch_info) struct here */
3827 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 3828 psrch_inf->unicode = true;
1da177e4 3829 else
4b18f2a9 3830 psrch_inf->unicode = false;
1da177e4
LT
3831 response_data = (char *) &pSMBr->hdr.Protocol +
3832 le16_to_cpu(pSMBr->t2.ParameterOffset);
3833 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3834 response_data = (char *)&pSMBr->hdr.Protocol +
3835 le16_to_cpu(pSMBr->t2.DataOffset);
790fe579 3836 if (psrch_inf->smallBuf)
d47d7c1a
SF
3837 cifs_small_buf_release(
3838 psrch_inf->ntwrk_buf_start);
3839 else
3840 cifs_buf_release(psrch_inf->ntwrk_buf_start);
1da177e4
LT
3841 psrch_inf->srch_entries_start = response_data;
3842 psrch_inf->ntwrk_buf_start = (char *)pSMB;
d47d7c1a 3843 psrch_inf->smallBuf = 0;
790fe579 3844 if (parms->EndofSearch)
4b18f2a9 3845 psrch_inf->endOfSearch = true;
1da177e4 3846 else
4b18f2a9 3847 psrch_inf->endOfSearch = false;
50c2f753
SF
3848 psrch_inf->entries_in_buffer =
3849 le16_to_cpu(parms->SearchCount);
1da177e4
LT
3850 psrch_inf->index_of_last_entry +=
3851 psrch_inf->entries_in_buffer;
b77d753c
SF
3852 lnoff = le16_to_cpu(parms->LastNameOffset);
3853 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3854 lnoff) {
b6b38f70 3855 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
3856 psrch_inf->last_entry = NULL;
3857 return rc;
3858 } else
3859 psrch_inf->last_entry =
3860 psrch_inf->srch_entries_start + lnoff;
3861
b6b38f70
JP
3862/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3863 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
1da177e4
LT
3864
3865 /* BB fixme add unlock here */
3866 }
3867
3868 }
3869
3870 /* BB On error, should we leave previous search buf (and count and
3871 last entry fields) intact or free the previous one? */
3872
3873 /* Note: On -EAGAIN error only caller can retry on handle based calls
3874 since file handle passed in no longer valid */
3875FNext2_err_exit:
3876 if (rc != 0)
3877 cifs_buf_release(pSMB);
1da177e4
LT
3878 return rc;
3879}
3880
3881int
50c2f753
SF
3882CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3883 const __u16 searchHandle)
1da177e4
LT
3884{
3885 int rc = 0;
3886 FINDCLOSE_REQ *pSMB = NULL;
1da177e4 3887
b6b38f70 3888 cFYI(1, "In CIFSSMBFindClose");
1da177e4
LT
3889 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3890
3891 /* no sense returning error if session restarted
3892 as file handle has been closed */
790fe579 3893 if (rc == -EAGAIN)
1da177e4
LT
3894 return 0;
3895 if (rc)
3896 return rc;
3897
1da177e4
LT
3898 pSMB->FileID = searchHandle;
3899 pSMB->ByteCount = 0;
133672ef 3900 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
ad7a2926 3901 if (rc)
b6b38f70 3902 cERROR(1, "Send error in FindClose = %d", rc);
ad7a2926 3903
a4544347 3904 cifs_stats_inc(&tcon->num_fclose);
1da177e4
LT
3905
3906 /* Since session is dead, search handle closed on server already */
3907 if (rc == -EAGAIN)
3908 rc = 0;
3909
3910 return rc;
3911}
3912
1da177e4
LT
3913int
3914CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
50c2f753 3915 const unsigned char *searchName,
ad7a2926 3916 __u64 *inode_number,
50c2f753 3917 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3918{
3919 int rc = 0;
3920 TRANSACTION2_QPI_REQ *pSMB = NULL;
3921 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3922 int name_len, bytes_returned;
3923 __u16 params, byte_count;
3924
b6b38f70 3925 cFYI(1, "In GetSrvInodeNum for %s", searchName);
790fe579 3926 if (tcon == NULL)
50c2f753 3927 return -ENODEV;
1da177e4
LT
3928
3929GetInodeNumberRetry:
3930 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 3931 (void **) &pSMBr);
1da177e4
LT
3932 if (rc)
3933 return rc;
3934
1da177e4
LT
3935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3936 name_len =
b1a45695 3937 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
50c2f753 3938 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3939 name_len++; /* trailing null */
3940 name_len *= 2;
50c2f753 3941 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3942 name_len = strnlen(searchName, PATH_MAX);
3943 name_len++; /* trailing null */
3944 strncpy(pSMB->FileName, searchName, name_len);
3945 }
3946
3947 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3948 pSMB->TotalDataCount = 0;
3949 pSMB->MaxParameterCount = cpu_to_le16(2);
3950 /* BB find exact max data count below from sess structure BB */
3951 pSMB->MaxDataCount = cpu_to_le16(4000);
3952 pSMB->MaxSetupCount = 0;
3953 pSMB->Reserved = 0;
3954 pSMB->Flags = 0;
3955 pSMB->Timeout = 0;
3956 pSMB->Reserved2 = 0;
3957 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3958 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3959 pSMB->DataCount = 0;
3960 pSMB->DataOffset = 0;
3961 pSMB->SetupCount = 1;
3962 pSMB->Reserved3 = 0;
3963 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3964 byte_count = params + 1 /* pad */ ;
3965 pSMB->TotalParameterCount = cpu_to_le16(params);
3966 pSMB->ParameterCount = pSMB->TotalParameterCount;
3967 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3968 pSMB->Reserved4 = 0;
3969 pSMB->hdr.smb_buf_length += byte_count;
3970 pSMB->ByteCount = cpu_to_le16(byte_count);
3971
3972 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3973 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3974 if (rc) {
b6b38f70 3975 cFYI(1, "error %d in QueryInternalInfo", rc);
1da177e4
LT
3976 } else {
3977 /* decode response */
3978 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3979 if (rc || (pSMBr->ByteCount < 2))
3980 /* BB also check enough total bytes returned */
3981 /* If rc should we check for EOPNOSUPP and
3982 disable the srvino flag? or in caller? */
3983 rc = -EIO; /* bad smb */
50c2f753 3984 else {
1da177e4
LT
3985 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3986 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
50c2f753 3987 struct file_internal_info *pfinfo;
1da177e4 3988 /* BB Do we need a cast or hash here ? */
790fe579 3989 if (count < 8) {
b6b38f70 3990 cFYI(1, "Illegal size ret in QryIntrnlInf");
1da177e4
LT
3991 rc = -EIO;
3992 goto GetInodeNumOut;
3993 }
3994 pfinfo = (struct file_internal_info *)
3995 (data_offset + (char *) &pSMBr->hdr.Protocol);
85a6dac5 3996 *inode_number = le64_to_cpu(pfinfo->UniqueId);
1da177e4
LT
3997 }
3998 }
3999GetInodeNumOut:
4000 cifs_buf_release(pSMB);
4001 if (rc == -EAGAIN)
4002 goto GetInodeNumberRetry;
4003 return rc;
4004}
1da177e4 4005
fec4585f
IM
4006/* parses DFS refferal V3 structure
4007 * caller is responsible for freeing target_nodes
4008 * returns:
4009 * on success - 0
4010 * on failure - errno
4011 */
4012static int
a1fe78f1 4013parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
fec4585f
IM
4014 unsigned int *num_of_nodes,
4015 struct dfs_info3_param **target_nodes,
2c55608f
IM
4016 const struct nls_table *nls_codepage, int remap,
4017 const char *searchName)
fec4585f
IM
4018{
4019 int i, rc = 0;
4020 char *data_end;
4021 bool is_unicode;
4022 struct dfs_referral_level_3 *ref;
4023
5ca33c6a
HH
4024 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4025 is_unicode = true;
4026 else
4027 is_unicode = false;
fec4585f
IM
4028 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4029
4030 if (*num_of_nodes < 1) {
b6b38f70
JP
4031 cERROR(1, "num_referrals: must be at least > 0,"
4032 "but we get num_referrals = %d\n", *num_of_nodes);
fec4585f 4033 rc = -EINVAL;
a1fe78f1 4034 goto parse_DFS_referrals_exit;
fec4585f
IM
4035 }
4036
4037 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
1d92cfd5 4038 if (ref->VersionNumber != cpu_to_le16(3)) {
b6b38f70
JP
4039 cERROR(1, "Referrals of V%d version are not supported,"
4040 "should be V3", le16_to_cpu(ref->VersionNumber));
fec4585f 4041 rc = -EINVAL;
a1fe78f1 4042 goto parse_DFS_referrals_exit;
fec4585f
IM
4043 }
4044
4045 /* get the upper boundary of the resp buffer */
4046 data_end = (char *)(&(pSMBr->PathConsumed)) +
4047 le16_to_cpu(pSMBr->t2.DataCount);
4048
f19159dc 4049 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
fec4585f 4050 *num_of_nodes,
b6b38f70 4051 le32_to_cpu(pSMBr->DFSFlags));
fec4585f
IM
4052
4053 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4054 *num_of_nodes, GFP_KERNEL);
4055 if (*target_nodes == NULL) {
b6b38f70 4056 cERROR(1, "Failed to allocate buffer for target_nodes\n");
fec4585f 4057 rc = -ENOMEM;
a1fe78f1 4058 goto parse_DFS_referrals_exit;
fec4585f
IM
4059 }
4060
3ad2f3fb 4061 /* collect necessary data from referrals */
fec4585f
IM
4062 for (i = 0; i < *num_of_nodes; i++) {
4063 char *temp;
4064 int max_len;
4065 struct dfs_info3_param *node = (*target_nodes)+i;
4066
0e0d2cf3 4067 node->flags = le32_to_cpu(pSMBr->DFSFlags);
2c55608f 4068 if (is_unicode) {
331c3135
JL
4069 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4070 GFP_KERNEL);
2920ee2b
SF
4071 if (tmp == NULL) {
4072 rc = -ENOMEM;
4073 goto parse_DFS_referrals_exit;
4074 }
2c55608f
IM
4075 cifsConvertToUCS((__le16 *) tmp, searchName,
4076 PATH_MAX, nls_codepage, remap);
69f801fc
JL
4077 node->path_consumed = cifs_ucs2_bytes(tmp,
4078 le16_to_cpu(pSMBr->PathConsumed),
2c55608f
IM
4079 nls_codepage);
4080 kfree(tmp);
4081 } else
4082 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4083
fec4585f
IM
4084 node->server_type = le16_to_cpu(ref->ServerType);
4085 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4086
4087 /* copy DfsPath */
4088 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4089 max_len = data_end - temp;
d185cda7
SF
4090 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4091 is_unicode, nls_codepage);
d8e2f53a
JL
4092 if (!node->path_name) {
4093 rc = -ENOMEM;
a1fe78f1 4094 goto parse_DFS_referrals_exit;
066ce689 4095 }
fec4585f
IM
4096
4097 /* copy link target UNC */
4098 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4099 max_len = data_end - temp;
d185cda7
SF
4100 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4101 is_unicode, nls_codepage);
d8e2f53a
JL
4102 if (!node->node_name)
4103 rc = -ENOMEM;
fec4585f
IM
4104 }
4105
a1fe78f1 4106parse_DFS_referrals_exit:
fec4585f
IM
4107 if (rc) {
4108 free_dfs_info_array(*target_nodes, *num_of_nodes);
4109 *target_nodes = NULL;
4110 *num_of_nodes = 0;
4111 }
4112 return rc;
4113}
4114
1da177e4
LT
4115int
4116CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4117 const unsigned char *searchName,
c2cf07d5
SF
4118 struct dfs_info3_param **target_nodes,
4119 unsigned int *num_of_nodes,
737b758c 4120 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4121{
4122/* TRANS2_GET_DFS_REFERRAL */
4123 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4124 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
1da177e4
LT
4125 int rc = 0;
4126 int bytes_returned;
4127 int name_len;
1da177e4 4128 __u16 params, byte_count;
c2cf07d5
SF
4129 *num_of_nodes = 0;
4130 *target_nodes = NULL;
1da177e4 4131
b6b38f70 4132 cFYI(1, "In GetDFSRefer the path %s", searchName);
1da177e4
LT
4133 if (ses == NULL)
4134 return -ENODEV;
4135getDFSRetry:
4136 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4137 (void **) &pSMBr);
4138 if (rc)
4139 return rc;
50c2f753
SF
4140
4141 /* server pointer checked in called function,
1982c344
SF
4142 but should never be null here anyway */
4143 pSMB->hdr.Mid = GetNextMid(ses->server);
1da177e4
LT
4144 pSMB->hdr.Tid = ses->ipc_tid;
4145 pSMB->hdr.Uid = ses->Suid;
26f57364 4146 if (ses->capabilities & CAP_STATUS32)
1da177e4 4147 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
26f57364 4148 if (ses->capabilities & CAP_DFS)
1da177e4 4149 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
1da177e4
LT
4150
4151 if (ses->capabilities & CAP_UNICODE) {
4152 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4153 name_len =
b1a45695 4154 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
737b758c 4155 searchName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
4156 name_len++; /* trailing null */
4157 name_len *= 2;
50c2f753 4158 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4159 name_len = strnlen(searchName, PATH_MAX);
4160 name_len++; /* trailing null */
4161 strncpy(pSMB->RequestFileName, searchName, name_len);
4162 }
4163
790fe579
SF
4164 if (ses->server) {
4165 if (ses->server->secMode &
1a4e15a0
SF
4166 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4167 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4168 }
4169
50c2f753 4170 pSMB->hdr.Uid = ses->Suid;
1a4e15a0 4171
1da177e4
LT
4172 params = 2 /* level */ + name_len /*includes null */ ;
4173 pSMB->TotalDataCount = 0;
4174 pSMB->DataCount = 0;
4175 pSMB->DataOffset = 0;
4176 pSMB->MaxParameterCount = 0;
582d21e5
SF
4177 /* BB find exact max SMB PDU from sess structure BB */
4178 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4179 pSMB->MaxSetupCount = 0;
4180 pSMB->Reserved = 0;
4181 pSMB->Flags = 0;
4182 pSMB->Timeout = 0;
4183 pSMB->Reserved2 = 0;
4184 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4185 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
1da177e4
LT
4186 pSMB->SetupCount = 1;
4187 pSMB->Reserved3 = 0;
4188 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4189 byte_count = params + 3 /* pad */ ;
4190 pSMB->ParameterCount = cpu_to_le16(params);
4191 pSMB->TotalParameterCount = pSMB->ParameterCount;
4192 pSMB->MaxReferralLevel = cpu_to_le16(3);
4193 pSMB->hdr.smb_buf_length += byte_count;
4194 pSMB->ByteCount = cpu_to_le16(byte_count);
4195
4196 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4198 if (rc) {
b6b38f70 4199 cFYI(1, "Send error in GetDFSRefer = %d", rc);
c2cf07d5
SF
4200 goto GetDFSRefExit;
4201 }
4202 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4203
c2cf07d5 4204 /* BB Also check if enough total bytes returned? */
fec4585f 4205 if (rc || (pSMBr->ByteCount < 17)) {
c2cf07d5 4206 rc = -EIO; /* bad smb */
fec4585f
IM
4207 goto GetDFSRefExit;
4208 }
c2cf07d5 4209
b6b38f70 4210 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
fec4585f 4211 pSMBr->ByteCount,
b6b38f70 4212 le16_to_cpu(pSMBr->t2.DataOffset));
1da177e4 4213
fec4585f 4214 /* parse returned result into more usable form */
a1fe78f1 4215 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
2c55608f
IM
4216 target_nodes, nls_codepage, remap,
4217 searchName);
c2cf07d5 4218
1da177e4 4219GetDFSRefExit:
0d817bc0 4220 cifs_buf_release(pSMB);
1da177e4
LT
4221
4222 if (rc == -EAGAIN)
4223 goto getDFSRetry;
4224
4225 return rc;
4226}
4227
20962438
SF
4228/* Query File System Info such as free space to old servers such as Win 9x */
4229int
4230SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4231{
4232/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4233 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4234 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4235 FILE_SYSTEM_ALLOC_INFO *response_data;
4236 int rc = 0;
4237 int bytes_returned = 0;
4238 __u16 params, byte_count;
4239
b6b38f70 4240 cFYI(1, "OldQFSInfo");
20962438
SF
4241oldQFSInfoRetry:
4242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4243 (void **) &pSMBr);
4244 if (rc)
4245 return rc;
20962438
SF
4246
4247 params = 2; /* level */
4248 pSMB->TotalDataCount = 0;
4249 pSMB->MaxParameterCount = cpu_to_le16(2);
4250 pSMB->MaxDataCount = cpu_to_le16(1000);
4251 pSMB->MaxSetupCount = 0;
4252 pSMB->Reserved = 0;
4253 pSMB->Flags = 0;
4254 pSMB->Timeout = 0;
4255 pSMB->Reserved2 = 0;
4256 byte_count = params + 1 /* pad */ ;
4257 pSMB->TotalParameterCount = cpu_to_le16(params);
4258 pSMB->ParameterCount = pSMB->TotalParameterCount;
4259 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4260 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4261 pSMB->DataCount = 0;
4262 pSMB->DataOffset = 0;
4263 pSMB->SetupCount = 1;
4264 pSMB->Reserved3 = 0;
4265 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4266 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4267 pSMB->hdr.smb_buf_length += byte_count;
4268 pSMB->ByteCount = cpu_to_le16(byte_count);
4269
4270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4272 if (rc) {
b6b38f70 4273 cFYI(1, "Send error in QFSInfo = %d", rc);
20962438
SF
4274 } else { /* decode response */
4275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4276
4277 if (rc || (pSMBr->ByteCount < 18))
4278 rc = -EIO; /* bad smb */
4279 else {
4280 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
b6b38f70
JP
4281 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4282 pSMBr->ByteCount, data_offset);
20962438 4283
50c2f753 4284 response_data = (FILE_SYSTEM_ALLOC_INFO *)
20962438
SF
4285 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4286 FSData->f_bsize =
4287 le16_to_cpu(response_data->BytesPerSector) *
4288 le32_to_cpu(response_data->
4289 SectorsPerAllocationUnit);
4290 FSData->f_blocks =
50c2f753 4291 le32_to_cpu(response_data->TotalAllocationUnits);
20962438
SF
4292 FSData->f_bfree = FSData->f_bavail =
4293 le32_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
4294 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4295 (unsigned long long)FSData->f_blocks,
4296 (unsigned long long)FSData->f_bfree,
4297 FSData->f_bsize);
20962438
SF
4298 }
4299 }
4300 cifs_buf_release(pSMB);
4301
4302 if (rc == -EAGAIN)
4303 goto oldQFSInfoRetry;
4304
4305 return rc;
4306}
4307
1da177e4 4308int
737b758c 4309CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
1da177e4
LT
4310{
4311/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4312 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4313 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4314 FILE_SYSTEM_INFO *response_data;
4315 int rc = 0;
4316 int bytes_returned = 0;
4317 __u16 params, byte_count;
4318
b6b38f70 4319 cFYI(1, "In QFSInfo");
1da177e4
LT
4320QFSInfoRetry:
4321 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4322 (void **) &pSMBr);
4323 if (rc)
4324 return rc;
4325
4326 params = 2; /* level */
4327 pSMB->TotalDataCount = 0;
4328 pSMB->MaxParameterCount = cpu_to_le16(2);
20962438 4329 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4330 pSMB->MaxSetupCount = 0;
4331 pSMB->Reserved = 0;
4332 pSMB->Flags = 0;
4333 pSMB->Timeout = 0;
4334 pSMB->Reserved2 = 0;
4335 byte_count = params + 1 /* pad */ ;
4336 pSMB->TotalParameterCount = cpu_to_le16(params);
4337 pSMB->ParameterCount = pSMB->TotalParameterCount;
4338 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4339 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4340 pSMB->DataCount = 0;
4341 pSMB->DataOffset = 0;
4342 pSMB->SetupCount = 1;
4343 pSMB->Reserved3 = 0;
4344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4346 pSMB->hdr.smb_buf_length += byte_count;
4347 pSMB->ByteCount = cpu_to_le16(byte_count);
4348
4349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4351 if (rc) {
b6b38f70 4352 cFYI(1, "Send error in QFSInfo = %d", rc);
1da177e4 4353 } else { /* decode response */
50c2f753 4354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4355
20962438 4356 if (rc || (pSMBr->ByteCount < 24))
1da177e4
LT
4357 rc = -EIO; /* bad smb */
4358 else {
4359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
4360
4361 response_data =
4362 (FILE_SYSTEM_INFO
4363 *) (((char *) &pSMBr->hdr.Protocol) +
4364 data_offset);
4365 FSData->f_bsize =
4366 le32_to_cpu(response_data->BytesPerSector) *
4367 le32_to_cpu(response_data->
4368 SectorsPerAllocationUnit);
4369 FSData->f_blocks =
4370 le64_to_cpu(response_data->TotalAllocationUnits);
4371 FSData->f_bfree = FSData->f_bavail =
4372 le64_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
4373 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4374 (unsigned long long)FSData->f_blocks,
4375 (unsigned long long)FSData->f_bfree,
4376 FSData->f_bsize);
1da177e4
LT
4377 }
4378 }
4379 cifs_buf_release(pSMB);
4380
4381 if (rc == -EAGAIN)
4382 goto QFSInfoRetry;
4383
4384 return rc;
4385}
4386
4387int
737b758c 4388CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4389{
4390/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4391 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4392 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4393 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4394 int rc = 0;
4395 int bytes_returned = 0;
4396 __u16 params, byte_count;
4397
b6b38f70 4398 cFYI(1, "In QFSAttributeInfo");
1da177e4
LT
4399QFSAttributeRetry:
4400 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4401 (void **) &pSMBr);
4402 if (rc)
4403 return rc;
4404
4405 params = 2; /* level */
4406 pSMB->TotalDataCount = 0;
4407 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4408 /* BB find exact max SMB PDU from sess structure BB */
4409 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4410 pSMB->MaxSetupCount = 0;
4411 pSMB->Reserved = 0;
4412 pSMB->Flags = 0;
4413 pSMB->Timeout = 0;
4414 pSMB->Reserved2 = 0;
4415 byte_count = params + 1 /* pad */ ;
4416 pSMB->TotalParameterCount = cpu_to_le16(params);
4417 pSMB->ParameterCount = pSMB->TotalParameterCount;
4418 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4419 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4420 pSMB->DataCount = 0;
4421 pSMB->DataOffset = 0;
4422 pSMB->SetupCount = 1;
4423 pSMB->Reserved3 = 0;
4424 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4425 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4426 pSMB->hdr.smb_buf_length += byte_count;
4427 pSMB->ByteCount = cpu_to_le16(byte_count);
4428
4429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4431 if (rc) {
b6b38f70 4432 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
1da177e4
LT
4433 } else { /* decode response */
4434 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4435
50c2f753
SF
4436 if (rc || (pSMBr->ByteCount < 13)) {
4437 /* BB also check if enough bytes returned */
1da177e4
LT
4438 rc = -EIO; /* bad smb */
4439 } else {
4440 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4441 response_data =
4442 (FILE_SYSTEM_ATTRIBUTE_INFO
4443 *) (((char *) &pSMBr->hdr.Protocol) +
4444 data_offset);
4445 memcpy(&tcon->fsAttrInfo, response_data,
26f57364 4446 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
1da177e4
LT
4447 }
4448 }
4449 cifs_buf_release(pSMB);
4450
4451 if (rc == -EAGAIN)
4452 goto QFSAttributeRetry;
4453
4454 return rc;
4455}
4456
4457int
737b758c 4458CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4459{
4460/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4461 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4462 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4463 FILE_SYSTEM_DEVICE_INFO *response_data;
4464 int rc = 0;
4465 int bytes_returned = 0;
4466 __u16 params, byte_count;
4467
b6b38f70 4468 cFYI(1, "In QFSDeviceInfo");
1da177e4
LT
4469QFSDeviceRetry:
4470 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4471 (void **) &pSMBr);
4472 if (rc)
4473 return rc;
4474
4475 params = 2; /* level */
4476 pSMB->TotalDataCount = 0;
4477 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4478 /* BB find exact max SMB PDU from sess structure BB */
4479 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4480 pSMB->MaxSetupCount = 0;
4481 pSMB->Reserved = 0;
4482 pSMB->Flags = 0;
4483 pSMB->Timeout = 0;
4484 pSMB->Reserved2 = 0;
4485 byte_count = params + 1 /* pad */ ;
4486 pSMB->TotalParameterCount = cpu_to_le16(params);
4487 pSMB->ParameterCount = pSMB->TotalParameterCount;
4488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4489 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4490
4491 pSMB->DataCount = 0;
4492 pSMB->DataOffset = 0;
4493 pSMB->SetupCount = 1;
4494 pSMB->Reserved3 = 0;
4495 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4496 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4497 pSMB->hdr.smb_buf_length += byte_count;
4498 pSMB->ByteCount = cpu_to_le16(byte_count);
4499
4500 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4502 if (rc) {
b6b38f70 4503 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
1da177e4
LT
4504 } else { /* decode response */
4505 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4506
630f3f0c 4507 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
1da177e4
LT
4508 rc = -EIO; /* bad smb */
4509 else {
4510 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4511 response_data =
737b758c
SF
4512 (FILE_SYSTEM_DEVICE_INFO *)
4513 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
4514 data_offset);
4515 memcpy(&tcon->fsDevInfo, response_data,
26f57364 4516 sizeof(FILE_SYSTEM_DEVICE_INFO));
1da177e4
LT
4517 }
4518 }
4519 cifs_buf_release(pSMB);
4520
4521 if (rc == -EAGAIN)
4522 goto QFSDeviceRetry;
4523
4524 return rc;
4525}
4526
4527int
737b758c 4528CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
1da177e4
LT
4529{
4530/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4531 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4532 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4533 FILE_SYSTEM_UNIX_INFO *response_data;
4534 int rc = 0;
4535 int bytes_returned = 0;
4536 __u16 params, byte_count;
4537
b6b38f70 4538 cFYI(1, "In QFSUnixInfo");
1da177e4
LT
4539QFSUnixRetry:
4540 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4541 (void **) &pSMBr);
4542 if (rc)
4543 return rc;
4544
4545 params = 2; /* level */
4546 pSMB->TotalDataCount = 0;
4547 pSMB->DataCount = 0;
4548 pSMB->DataOffset = 0;
4549 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4550 /* BB find exact max SMB PDU from sess structure BB */
4551 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
4552 pSMB->MaxSetupCount = 0;
4553 pSMB->Reserved = 0;
4554 pSMB->Flags = 0;
4555 pSMB->Timeout = 0;
4556 pSMB->Reserved2 = 0;
4557 byte_count = params + 1 /* pad */ ;
4558 pSMB->ParameterCount = cpu_to_le16(params);
4559 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
4560 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4561 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4562 pSMB->SetupCount = 1;
4563 pSMB->Reserved3 = 0;
4564 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4565 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4566 pSMB->hdr.smb_buf_length += byte_count;
4567 pSMB->ByteCount = cpu_to_le16(byte_count);
4568
4569 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4570 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4571 if (rc) {
b6b38f70 4572 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
4573 } else { /* decode response */
4574 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4575
4576 if (rc || (pSMBr->ByteCount < 13)) {
4577 rc = -EIO; /* bad smb */
4578 } else {
4579 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4580 response_data =
4581 (FILE_SYSTEM_UNIX_INFO
4582 *) (((char *) &pSMBr->hdr.Protocol) +
4583 data_offset);
4584 memcpy(&tcon->fsUnixInfo, response_data,
26f57364 4585 sizeof(FILE_SYSTEM_UNIX_INFO));
1da177e4
LT
4586 }
4587 }
4588 cifs_buf_release(pSMB);
4589
4590 if (rc == -EAGAIN)
4591 goto QFSUnixRetry;
4592
4593
4594 return rc;
4595}
4596
ac67055e 4597int
45abc6ee 4598CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
ac67055e
JA
4599{
4600/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4601 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4602 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4603 int rc = 0;
4604 int bytes_returned = 0;
4605 __u16 params, param_offset, offset, byte_count;
4606
b6b38f70 4607 cFYI(1, "In SETFSUnixInfo");
ac67055e 4608SETFSUnixRetry:
f26282c9 4609 /* BB switch to small buf init to save memory */
ac67055e
JA
4610 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4611 (void **) &pSMBr);
4612 if (rc)
4613 return rc;
4614
4615 params = 4; /* 2 bytes zero followed by info level. */
4616 pSMB->MaxSetupCount = 0;
4617 pSMB->Reserved = 0;
4618 pSMB->Flags = 0;
4619 pSMB->Timeout = 0;
4620 pSMB->Reserved2 = 0;
50c2f753
SF
4621 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4622 - 4;
ac67055e
JA
4623 offset = param_offset + params;
4624
4625 pSMB->MaxParameterCount = cpu_to_le16(4);
582d21e5
SF
4626 /* BB find exact max SMB PDU from sess structure BB */
4627 pSMB->MaxDataCount = cpu_to_le16(100);
ac67055e
JA
4628 pSMB->SetupCount = 1;
4629 pSMB->Reserved3 = 0;
4630 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4631 byte_count = 1 /* pad */ + params + 12;
4632
4633 pSMB->DataCount = cpu_to_le16(12);
4634 pSMB->ParameterCount = cpu_to_le16(params);
4635 pSMB->TotalDataCount = pSMB->DataCount;
4636 pSMB->TotalParameterCount = pSMB->ParameterCount;
4637 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4638 pSMB->DataOffset = cpu_to_le16(offset);
4639
4640 /* Params. */
4641 pSMB->FileNum = 0;
4642 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4643
4644 /* Data. */
4645 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4646 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4647 pSMB->ClientUnixCap = cpu_to_le64(cap);
4648
4649 pSMB->hdr.smb_buf_length += byte_count;
4650 pSMB->ByteCount = cpu_to_le16(byte_count);
4651
4652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4654 if (rc) {
b6b38f70 4655 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
ac67055e
JA
4656 } else { /* decode response */
4657 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
ad7a2926 4658 if (rc)
ac67055e 4659 rc = -EIO; /* bad smb */
ac67055e
JA
4660 }
4661 cifs_buf_release(pSMB);
4662
4663 if (rc == -EAGAIN)
4664 goto SETFSUnixRetry;
4665
4666 return rc;
4667}
4668
4669
1da177e4
LT
4670
4671int
4672CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
737b758c 4673 struct kstatfs *FSData)
1da177e4
LT
4674{
4675/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4676 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4677 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4678 FILE_SYSTEM_POSIX_INFO *response_data;
4679 int rc = 0;
4680 int bytes_returned = 0;
4681 __u16 params, byte_count;
4682
b6b38f70 4683 cFYI(1, "In QFSPosixInfo");
1da177e4
LT
4684QFSPosixRetry:
4685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4686 (void **) &pSMBr);
4687 if (rc)
4688 return rc;
4689
4690 params = 2; /* level */
4691 pSMB->TotalDataCount = 0;
4692 pSMB->DataCount = 0;
4693 pSMB->DataOffset = 0;
4694 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4695 /* BB find exact max SMB PDU from sess structure BB */
4696 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
4697 pSMB->MaxSetupCount = 0;
4698 pSMB->Reserved = 0;
4699 pSMB->Flags = 0;
4700 pSMB->Timeout = 0;
4701 pSMB->Reserved2 = 0;
4702 byte_count = params + 1 /* pad */ ;
4703 pSMB->ParameterCount = cpu_to_le16(params);
4704 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
4705 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4706 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4707 pSMB->SetupCount = 1;
4708 pSMB->Reserved3 = 0;
4709 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4710 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4711 pSMB->hdr.smb_buf_length += byte_count;
4712 pSMB->ByteCount = cpu_to_le16(byte_count);
4713
4714 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4715 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4716 if (rc) {
b6b38f70 4717 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
4718 } else { /* decode response */
4719 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4720
4721 if (rc || (pSMBr->ByteCount < 13)) {
4722 rc = -EIO; /* bad smb */
4723 } else {
4724 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4725 response_data =
4726 (FILE_SYSTEM_POSIX_INFO
4727 *) (((char *) &pSMBr->hdr.Protocol) +
4728 data_offset);
4729 FSData->f_bsize =
4730 le32_to_cpu(response_data->BlockSize);
4731 FSData->f_blocks =
4732 le64_to_cpu(response_data->TotalBlocks);
4733 FSData->f_bfree =
4734 le64_to_cpu(response_data->BlocksAvail);
790fe579 4735 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
1da177e4
LT
4736 FSData->f_bavail = FSData->f_bfree;
4737 } else {
4738 FSData->f_bavail =
50c2f753 4739 le64_to_cpu(response_data->UserBlocksAvail);
1da177e4 4740 }
790fe579 4741 if (response_data->TotalFileNodes != cpu_to_le64(-1))
1da177e4 4742 FSData->f_files =
50c2f753 4743 le64_to_cpu(response_data->TotalFileNodes);
790fe579 4744 if (response_data->FreeFileNodes != cpu_to_le64(-1))
1da177e4 4745 FSData->f_ffree =
50c2f753 4746 le64_to_cpu(response_data->FreeFileNodes);
1da177e4
LT
4747 }
4748 }
4749 cifs_buf_release(pSMB);
4750
4751 if (rc == -EAGAIN)
4752 goto QFSPosixRetry;
4753
4754 return rc;
4755}
4756
4757
50c2f753
SF
4758/* We can not use write of zero bytes trick to
4759 set file size due to need for large file support. Also note that
4760 this SetPathInfo is preferred to SetFileInfo based method in next
1da177e4
LT
4761 routine which is only needed to work around a sharing violation bug
4762 in Samba which this routine can run into */
4763
4764int
4765CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4b18f2a9 4766 __u64 size, bool SetAllocation,
737b758c 4767 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4768{
4769 struct smb_com_transaction2_spi_req *pSMB = NULL;
4770 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4771 struct file_end_of_file_info *parm_data;
4772 int name_len;
4773 int rc = 0;
4774 int bytes_returned = 0;
4775 __u16 params, byte_count, data_count, param_offset, offset;
4776
b6b38f70 4777 cFYI(1, "In SetEOF");
1da177e4
LT
4778SetEOFRetry:
4779 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4780 (void **) &pSMBr);
4781 if (rc)
4782 return rc;
4783
4784 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4785 name_len =
b1a45695 4786 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 4787 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4788 name_len++; /* trailing null */
4789 name_len *= 2;
3e87d803 4790 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4791 name_len = strnlen(fileName, PATH_MAX);
4792 name_len++; /* trailing null */
4793 strncpy(pSMB->FileName, fileName, name_len);
4794 }
4795 params = 6 + name_len;
26f57364 4796 data_count = sizeof(struct file_end_of_file_info);
1da177e4 4797 pSMB->MaxParameterCount = cpu_to_le16(2);
3e87d803 4798 pSMB->MaxDataCount = cpu_to_le16(4100);
1da177e4
LT
4799 pSMB->MaxSetupCount = 0;
4800 pSMB->Reserved = 0;
4801 pSMB->Flags = 0;
4802 pSMB->Timeout = 0;
4803 pSMB->Reserved2 = 0;
4804 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 4805 InformationLevel) - 4;
1da177e4 4806 offset = param_offset + params;
790fe579 4807 if (SetAllocation) {
50c2f753
SF
4808 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4809 pSMB->InformationLevel =
4810 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4811 else
4812 pSMB->InformationLevel =
4813 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4814 } else /* Set File Size */ {
1da177e4
LT
4815 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816 pSMB->InformationLevel =
50c2f753 4817 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
4818 else
4819 pSMB->InformationLevel =
50c2f753 4820 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
4821 }
4822
4823 parm_data =
4824 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4825 offset);
4826 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4827 pSMB->DataOffset = cpu_to_le16(offset);
4828 pSMB->SetupCount = 1;
4829 pSMB->Reserved3 = 0;
4830 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4831 byte_count = 3 /* pad */ + params + data_count;
4832 pSMB->DataCount = cpu_to_le16(data_count);
4833 pSMB->TotalDataCount = pSMB->DataCount;
4834 pSMB->ParameterCount = cpu_to_le16(params);
4835 pSMB->TotalParameterCount = pSMB->ParameterCount;
4836 pSMB->Reserved4 = 0;
4837 pSMB->hdr.smb_buf_length += byte_count;
4838 parm_data->FileSize = cpu_to_le64(size);
4839 pSMB->ByteCount = cpu_to_le16(byte_count);
4840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 4842 if (rc)
b6b38f70 4843 cFYI(1, "SetPathInfo (file size) returned %d", rc);
1da177e4
LT
4844
4845 cifs_buf_release(pSMB);
4846
4847 if (rc == -EAGAIN)
4848 goto SetEOFRetry;
4849
4850 return rc;
4851}
4852
4853int
50c2f753 4854CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4b18f2a9 4855 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
1da177e4
LT
4856{
4857 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
4858 char *data_offset;
4859 struct file_end_of_file_info *parm_data;
4860 int rc = 0;
1da177e4
LT
4861 __u16 params, param_offset, offset, byte_count, count;
4862
b6b38f70
JP
4863 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4864 (long long)size);
cd63499c
SF
4865 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4866
1da177e4
LT
4867 if (rc)
4868 return rc;
4869
4870 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4871 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 4872
1da177e4
LT
4873 params = 6;
4874 pSMB->MaxSetupCount = 0;
4875 pSMB->Reserved = 0;
4876 pSMB->Flags = 0;
4877 pSMB->Timeout = 0;
4878 pSMB->Reserved2 = 0;
4879 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4880 offset = param_offset + params;
4881
50c2f753 4882 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1da177e4
LT
4883
4884 count = sizeof(struct file_end_of_file_info);
4885 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4886 /* BB find exact max SMB PDU from sess structure BB */
4887 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4888 pSMB->SetupCount = 1;
4889 pSMB->Reserved3 = 0;
4890 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4891 byte_count = 3 /* pad */ + params + count;
4892 pSMB->DataCount = cpu_to_le16(count);
4893 pSMB->ParameterCount = cpu_to_le16(params);
4894 pSMB->TotalDataCount = pSMB->DataCount;
4895 pSMB->TotalParameterCount = pSMB->ParameterCount;
4896 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4897 parm_data =
50c2f753
SF
4898 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4899 + offset);
1da177e4
LT
4900 pSMB->DataOffset = cpu_to_le16(offset);
4901 parm_data->FileSize = cpu_to_le64(size);
4902 pSMB->Fid = fid;
790fe579 4903 if (SetAllocation) {
1da177e4
LT
4904 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4905 pSMB->InformationLevel =
4906 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4907 else
4908 pSMB->InformationLevel =
4909 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
50c2f753 4910 } else /* Set File Size */ {
1da177e4
LT
4911 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4912 pSMB->InformationLevel =
50c2f753 4913 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
4914 else
4915 pSMB->InformationLevel =
50c2f753 4916 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
4917 }
4918 pSMB->Reserved4 = 0;
4919 pSMB->hdr.smb_buf_length += byte_count;
4920 pSMB->ByteCount = cpu_to_le16(byte_count);
133672ef 4921 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1da177e4 4922 if (rc) {
b6b38f70 4923 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
1da177e4
LT
4924 }
4925
50c2f753 4926 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
4927 since file handle passed in no longer valid */
4928
4929 return rc;
4930}
4931
50c2f753 4932/* Some legacy servers such as NT4 require that the file times be set on
1da177e4
LT
4933 an open handle, rather than by pathname - this is awkward due to
4934 potential access conflicts on the open, but it is unavoidable for these
4935 old servers since the only other choice is to go from 100 nanosecond DCE
4936 time and resort to the original setpathinfo level which takes the ancient
4937 DOS time format with 2 second granularity */
4938int
2dd2dfa0
JL
4939CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4940 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
1da177e4
LT
4941{
4942 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
4943 char *data_offset;
4944 int rc = 0;
1da177e4
LT
4945 __u16 params, param_offset, offset, byte_count, count;
4946
b6b38f70 4947 cFYI(1, "Set Times (via SetFileInfo)");
cd63499c
SF
4948 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4949
1da177e4
LT
4950 if (rc)
4951 return rc;
4952
2dd2dfa0
JL
4953 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4954 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 4955
1da177e4
LT
4956 params = 6;
4957 pSMB->MaxSetupCount = 0;
4958 pSMB->Reserved = 0;
4959 pSMB->Flags = 0;
4960 pSMB->Timeout = 0;
4961 pSMB->Reserved2 = 0;
4962 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4963 offset = param_offset + params;
4964
50c2f753 4965 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1da177e4 4966
26f57364 4967 count = sizeof(FILE_BASIC_INFO);
1da177e4 4968 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4969 /* BB find max SMB PDU from sess */
4970 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4971 pSMB->SetupCount = 1;
4972 pSMB->Reserved3 = 0;
4973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4974 byte_count = 3 /* pad */ + params + count;
4975 pSMB->DataCount = cpu_to_le16(count);
4976 pSMB->ParameterCount = cpu_to_le16(params);
4977 pSMB->TotalDataCount = pSMB->DataCount;
4978 pSMB->TotalParameterCount = pSMB->ParameterCount;
4979 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4980 pSMB->DataOffset = cpu_to_le16(offset);
4981 pSMB->Fid = fid;
4982 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4983 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4984 else
4985 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4986 pSMB->Reserved4 = 0;
4987 pSMB->hdr.smb_buf_length += byte_count;
4988 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 4989 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
133672ef 4990 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
ad7a2926 4991 if (rc)
b6b38f70 4992 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
1da177e4 4993
50c2f753 4994 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
4995 since file handle passed in no longer valid */
4996
4997 return rc;
4998}
4999
6d22f098
JL
5000int
5001CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5002 bool delete_file, __u16 fid, __u32 pid_of_opener)
5003{
5004 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5005 char *data_offset;
5006 int rc = 0;
5007 __u16 params, param_offset, offset, byte_count, count;
5008
b6b38f70 5009 cFYI(1, "Set File Disposition (via SetFileInfo)");
6d22f098
JL
5010 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5011
5012 if (rc)
5013 return rc;
5014
5015 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5016 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5017
5018 params = 6;
5019 pSMB->MaxSetupCount = 0;
5020 pSMB->Reserved = 0;
5021 pSMB->Flags = 0;
5022 pSMB->Timeout = 0;
5023 pSMB->Reserved2 = 0;
5024 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5025 offset = param_offset + params;
5026
5027 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5028
5029 count = 1;
5030 pSMB->MaxParameterCount = cpu_to_le16(2);
5031 /* BB find max SMB PDU from sess */
5032 pSMB->MaxDataCount = cpu_to_le16(1000);
5033 pSMB->SetupCount = 1;
5034 pSMB->Reserved3 = 0;
5035 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5036 byte_count = 3 /* pad */ + params + count;
5037 pSMB->DataCount = cpu_to_le16(count);
5038 pSMB->ParameterCount = cpu_to_le16(params);
5039 pSMB->TotalDataCount = pSMB->DataCount;
5040 pSMB->TotalParameterCount = pSMB->ParameterCount;
5041 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5042 pSMB->DataOffset = cpu_to_le16(offset);
5043 pSMB->Fid = fid;
5044 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5045 pSMB->Reserved4 = 0;
5046 pSMB->hdr.smb_buf_length += byte_count;
5047 pSMB->ByteCount = cpu_to_le16(byte_count);
5048 *data_offset = delete_file ? 1 : 0;
5049 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5050 if (rc)
b6b38f70 5051 cFYI(1, "Send error in SetFileDisposition = %d", rc);
6d22f098
JL
5052
5053 return rc;
5054}
1da177e4
LT
5055
5056int
6fc000e5
JL
5057CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5058 const char *fileName, const FILE_BASIC_INFO *data,
5059 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5060{
5061 TRANSACTION2_SPI_REQ *pSMB = NULL;
5062 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5063 int name_len;
5064 int rc = 0;
5065 int bytes_returned = 0;
5066 char *data_offset;
5067 __u16 params, param_offset, offset, byte_count, count;
5068
b6b38f70 5069 cFYI(1, "In SetTimes");
1da177e4
LT
5070
5071SetTimesRetry:
5072 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5073 (void **) &pSMBr);
5074 if (rc)
5075 return rc;
5076
5077 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5078 name_len =
b1a45695 5079 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 5080 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5081 name_len++; /* trailing null */
5082 name_len *= 2;
50c2f753 5083 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5084 name_len = strnlen(fileName, PATH_MAX);
5085 name_len++; /* trailing null */
5086 strncpy(pSMB->FileName, fileName, name_len);
5087 }
5088
5089 params = 6 + name_len;
26f57364 5090 count = sizeof(FILE_BASIC_INFO);
1da177e4 5091 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5092 /* BB find max SMB PDU from sess structure BB */
5093 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5094 pSMB->MaxSetupCount = 0;
5095 pSMB->Reserved = 0;
5096 pSMB->Flags = 0;
5097 pSMB->Timeout = 0;
5098 pSMB->Reserved2 = 0;
5099 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5100 InformationLevel) - 4;
1da177e4
LT
5101 offset = param_offset + params;
5102 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5103 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5104 pSMB->DataOffset = cpu_to_le16(offset);
5105 pSMB->SetupCount = 1;
5106 pSMB->Reserved3 = 0;
5107 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5108 byte_count = 3 /* pad */ + params + count;
5109
5110 pSMB->DataCount = cpu_to_le16(count);
5111 pSMB->ParameterCount = cpu_to_le16(params);
5112 pSMB->TotalDataCount = pSMB->DataCount;
5113 pSMB->TotalParameterCount = pSMB->ParameterCount;
5114 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5115 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5116 else
5117 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5118 pSMB->Reserved4 = 0;
5119 pSMB->hdr.smb_buf_length += byte_count;
26f57364 5120 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
1da177e4
LT
5121 pSMB->ByteCount = cpu_to_le16(byte_count);
5122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5124 if (rc)
b6b38f70 5125 cFYI(1, "SetPathInfo (times) returned %d", rc);
1da177e4
LT
5126
5127 cifs_buf_release(pSMB);
5128
5129 if (rc == -EAGAIN)
5130 goto SetTimesRetry;
5131
5132 return rc;
5133}
5134
5135/* Can not be used to set time stamps yet (due to old DOS time format) */
5136/* Can be used to set attributes */
5137#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5138 handling it anyway and NT4 was what we thought it would be needed for
5139 Do not delete it until we prove whether needed for Win9x though */
5140int
5141CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5142 __u16 dos_attrs, const struct nls_table *nls_codepage)
5143{
5144 SETATTR_REQ *pSMB = NULL;
5145 SETATTR_RSP *pSMBr = NULL;
5146 int rc = 0;
5147 int bytes_returned;
5148 int name_len;
5149
b6b38f70 5150 cFYI(1, "In SetAttrLegacy");
1da177e4
LT
5151
5152SetAttrLgcyRetry:
5153 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5154 (void **) &pSMBr);
5155 if (rc)
5156 return rc;
5157
5158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5159 name_len =
50c2f753 5160 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
1da177e4
LT
5161 PATH_MAX, nls_codepage);
5162 name_len++; /* trailing null */
5163 name_len *= 2;
50c2f753 5164 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5165 name_len = strnlen(fileName, PATH_MAX);
5166 name_len++; /* trailing null */
5167 strncpy(pSMB->fileName, fileName, name_len);
5168 }
5169 pSMB->attr = cpu_to_le16(dos_attrs);
5170 pSMB->BufferFormat = 0x04;
5171 pSMB->hdr.smb_buf_length += name_len + 1;
5172 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5173 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5174 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5175 if (rc)
b6b38f70 5176 cFYI(1, "Error in LegacySetAttr = %d", rc);
1da177e4
LT
5177
5178 cifs_buf_release(pSMB);
5179
5180 if (rc == -EAGAIN)
5181 goto SetAttrLgcyRetry;
5182
5183 return rc;
5184}
5185#endif /* temporarily unneeded SetAttr legacy function */
5186
654cf14a
JL
5187static void
5188cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5189 const struct cifs_unix_set_info_args *args)
5190{
5191 u64 mode = args->mode;
5192
5193 /*
5194 * Samba server ignores set of file size to zero due to bugs in some
5195 * older clients, but we should be precise - we use SetFileSize to
5196 * set file size and do not want to truncate file size to zero
5197 * accidently as happened on one Samba server beta by putting
5198 * zero instead of -1 here
5199 */
5200 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5201 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5202 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5203 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5204 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5205 data_offset->Uid = cpu_to_le64(args->uid);
5206 data_offset->Gid = cpu_to_le64(args->gid);
5207 /* better to leave device as zero when it is */
5208 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5209 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5210 data_offset->Permissions = cpu_to_le64(mode);
5211
5212 if (S_ISREG(mode))
5213 data_offset->Type = cpu_to_le32(UNIX_FILE);
5214 else if (S_ISDIR(mode))
5215 data_offset->Type = cpu_to_le32(UNIX_DIR);
5216 else if (S_ISLNK(mode))
5217 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5218 else if (S_ISCHR(mode))
5219 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5220 else if (S_ISBLK(mode))
5221 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5222 else if (S_ISFIFO(mode))
5223 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5224 else if (S_ISSOCK(mode))
5225 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5226}
5227
3bbeeb3c
JL
5228int
5229CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5230 const struct cifs_unix_set_info_args *args,
5231 u16 fid, u32 pid_of_opener)
5232{
5233 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5234 FILE_UNIX_BASIC_INFO *data_offset;
5235 int rc = 0;
5236 u16 params, param_offset, offset, byte_count, count;
5237
b6b38f70 5238 cFYI(1, "Set Unix Info (via SetFileInfo)");
3bbeeb3c
JL
5239 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5240
5241 if (rc)
5242 return rc;
5243
5244 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5245 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5246
5247 params = 6;
5248 pSMB->MaxSetupCount = 0;
5249 pSMB->Reserved = 0;
5250 pSMB->Flags = 0;
5251 pSMB->Timeout = 0;
5252 pSMB->Reserved2 = 0;
5253 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5254 offset = param_offset + params;
5255
5256 data_offset = (FILE_UNIX_BASIC_INFO *)
5257 ((char *)(&pSMB->hdr.Protocol) + offset);
5258 count = sizeof(FILE_UNIX_BASIC_INFO);
5259
5260 pSMB->MaxParameterCount = cpu_to_le16(2);
5261 /* BB find max SMB PDU from sess */
5262 pSMB->MaxDataCount = cpu_to_le16(1000);
5263 pSMB->SetupCount = 1;
5264 pSMB->Reserved3 = 0;
5265 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5266 byte_count = 3 /* pad */ + params + count;
5267 pSMB->DataCount = cpu_to_le16(count);
5268 pSMB->ParameterCount = cpu_to_le16(params);
5269 pSMB->TotalDataCount = pSMB->DataCount;
5270 pSMB->TotalParameterCount = pSMB->ParameterCount;
5271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5272 pSMB->DataOffset = cpu_to_le16(offset);
5273 pSMB->Fid = fid;
5274 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5275 pSMB->Reserved4 = 0;
5276 pSMB->hdr.smb_buf_length += byte_count;
5277 pSMB->ByteCount = cpu_to_le16(byte_count);
5278
5279 cifs_fill_unix_set_info(data_offset, args);
5280
5281 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5282 if (rc)
b6b38f70 5283 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
3bbeeb3c
JL
5284
5285 /* Note: On -EAGAIN error only caller can retry on handle based calls
5286 since file handle passed in no longer valid */
5287
5288 return rc;
5289}
5290
1da177e4 5291int
01ea95e3
JL
5292CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5293 const struct cifs_unix_set_info_args *args,
5294 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5295{
5296 TRANSACTION2_SPI_REQ *pSMB = NULL;
5297 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5298 int name_len;
5299 int rc = 0;
5300 int bytes_returned = 0;
5301 FILE_UNIX_BASIC_INFO *data_offset;
5302 __u16 params, param_offset, offset, count, byte_count;
5303
b6b38f70 5304 cFYI(1, "In SetUID/GID/Mode");
1da177e4
LT
5305setPermsRetry:
5306 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5307 (void **) &pSMBr);
5308 if (rc)
5309 return rc;
5310
5311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5312 name_len =
50c2f753 5313 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 5314 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5315 name_len++; /* trailing null */
5316 name_len *= 2;
3e87d803 5317 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5318 name_len = strnlen(fileName, PATH_MAX);
5319 name_len++; /* trailing null */
5320 strncpy(pSMB->FileName, fileName, name_len);
5321 }
5322
5323 params = 6 + name_len;
26f57364 5324 count = sizeof(FILE_UNIX_BASIC_INFO);
1da177e4 5325 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5326 /* BB find max SMB PDU from sess structure BB */
5327 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5328 pSMB->MaxSetupCount = 0;
5329 pSMB->Reserved = 0;
5330 pSMB->Flags = 0;
5331 pSMB->Timeout = 0;
5332 pSMB->Reserved2 = 0;
5333 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5334 InformationLevel) - 4;
1da177e4
LT
5335 offset = param_offset + params;
5336 data_offset =
5337 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5338 offset);
5339 memset(data_offset, 0, count);
5340 pSMB->DataOffset = cpu_to_le16(offset);
5341 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5342 pSMB->SetupCount = 1;
5343 pSMB->Reserved3 = 0;
5344 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5345 byte_count = 3 /* pad */ + params + count;
5346 pSMB->ParameterCount = cpu_to_le16(params);
5347 pSMB->DataCount = cpu_to_le16(count);
5348 pSMB->TotalParameterCount = pSMB->ParameterCount;
5349 pSMB->TotalDataCount = pSMB->DataCount;
5350 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5351 pSMB->Reserved4 = 0;
5352 pSMB->hdr.smb_buf_length += byte_count;
1da177e4 5353
654cf14a 5354 cifs_fill_unix_set_info(data_offset, args);
1da177e4
LT
5355
5356 pSMB->ByteCount = cpu_to_le16(byte_count);
5357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5359 if (rc)
b6b38f70 5360 cFYI(1, "SetPathInfo (perms) returned %d", rc);
1da177e4 5361
0d817bc0 5362 cifs_buf_release(pSMB);
1da177e4
LT
5363 if (rc == -EAGAIN)
5364 goto setPermsRetry;
5365 return rc;
5366}
5367
50c2f753 5368int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
167a251a 5369 const int notify_subdirs, const __u16 netfid,
50c2f753 5370 __u32 filter, struct file *pfile, int multishot,
167a251a 5371 const struct nls_table *nls_codepage)
1da177e4
LT
5372{
5373 int rc = 0;
50c2f753
SF
5374 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5375 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
abb15b8a 5376 struct dir_notify_req *dnotify_req;
1da177e4
LT
5377 int bytes_returned;
5378
b6b38f70 5379 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
1da177e4 5380 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
50c2f753 5381 (void **) &pSMBr);
1da177e4
LT
5382 if (rc)
5383 return rc;
5384
5385 pSMB->TotalParameterCount = 0 ;
5386 pSMB->TotalDataCount = 0;
5387 pSMB->MaxParameterCount = cpu_to_le32(2);
5388 /* BB find exact data count max from sess structure BB */
5389 pSMB->MaxDataCount = 0; /* same in little endian or be */
0a4b92c0
SF
5390/* BB VERIFY verify which is correct for above BB */
5391 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5392 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5393
1da177e4
LT
5394 pSMB->MaxSetupCount = 4;
5395 pSMB->Reserved = 0;
5396 pSMB->ParameterOffset = 0;
5397 pSMB->DataCount = 0;
5398 pSMB->DataOffset = 0;
5399 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5400 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5401 pSMB->ParameterCount = pSMB->TotalParameterCount;
790fe579 5402 if (notify_subdirs)
1da177e4
LT
5403 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5404 pSMB->Reserved2 = 0;
5405 pSMB->CompletionFilter = cpu_to_le32(filter);
5406 pSMB->Fid = netfid; /* file handle always le */
5407 pSMB->ByteCount = 0;
5408
5409 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
133672ef
SF
5410 (struct smb_hdr *)pSMBr, &bytes_returned,
5411 CIFS_ASYNC_OP);
1da177e4 5412 if (rc) {
b6b38f70 5413 cFYI(1, "Error in Notify = %d", rc);
ff5dbd9e
SF
5414 } else {
5415 /* Add file to outstanding requests */
50c2f753 5416 /* BB change to kmem cache alloc */
5cbded58 5417 dnotify_req = kmalloc(
47c786e7
SF
5418 sizeof(struct dir_notify_req),
5419 GFP_KERNEL);
790fe579 5420 if (dnotify_req) {
47c786e7
SF
5421 dnotify_req->Pid = pSMB->hdr.Pid;
5422 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5423 dnotify_req->Mid = pSMB->hdr.Mid;
5424 dnotify_req->Tid = pSMB->hdr.Tid;
5425 dnotify_req->Uid = pSMB->hdr.Uid;
5426 dnotify_req->netfid = netfid;
5427 dnotify_req->pfile = pfile;
5428 dnotify_req->filter = filter;
5429 dnotify_req->multishot = multishot;
5430 spin_lock(&GlobalMid_Lock);
50c2f753 5431 list_add_tail(&dnotify_req->lhead,
47c786e7
SF
5432 &GlobalDnotifyReqList);
5433 spin_unlock(&GlobalMid_Lock);
50c2f753 5434 } else
47c786e7 5435 rc = -ENOMEM;
1da177e4
LT
5436 }
5437 cifs_buf_release(pSMB);
50c2f753 5438 return rc;
1da177e4 5439}
31c0519f 5440
1da177e4 5441#ifdef CONFIG_CIFS_XATTR
31c0519f
JL
5442/*
5443 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5444 * function used by listxattr and getxattr type calls. When ea_name is set,
5445 * it looks for that attribute name and stuffs that value into the EAData
5446 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5447 * buffer. In both cases, the return value is either the length of the
5448 * resulting data or a negative error code. If EAData is a NULL pointer then
5449 * the data isn't copied to it, but the length is returned.
5450 */
1da177e4
LT
5451ssize_t
5452CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
31c0519f
JL
5453 const unsigned char *searchName, const unsigned char *ea_name,
5454 char *EAData, size_t buf_size,
5455 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5456{
5457 /* BB assumes one setup word */
5458 TRANSACTION2_QPI_REQ *pSMB = NULL;
5459 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5460 int rc = 0;
5461 int bytes_returned;
6e462b9f 5462 int list_len;
f0d3868b 5463 struct fealist *ea_response_data;
50c2f753
SF
5464 struct fea *temp_fea;
5465 char *temp_ptr;
0cd126b5 5466 char *end_of_smb;
f0d3868b 5467 __u16 params, byte_count, data_offset;
1da177e4 5468
b6b38f70 5469 cFYI(1, "In Query All EAs path %s", searchName);
1da177e4
LT
5470QAllEAsRetry:
5471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5472 (void **) &pSMBr);
5473 if (rc)
5474 return rc;
5475
5476 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6e462b9f 5477 list_len =
50c2f753 5478 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
737b758c 5479 PATH_MAX, nls_codepage, remap);
6e462b9f
JL
5480 list_len++; /* trailing null */
5481 list_len *= 2;
1da177e4 5482 } else { /* BB improve the check for buffer overruns BB */
6e462b9f
JL
5483 list_len = strnlen(searchName, PATH_MAX);
5484 list_len++; /* trailing null */
5485 strncpy(pSMB->FileName, searchName, list_len);
1da177e4
LT
5486 }
5487
6e462b9f 5488 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
1da177e4
LT
5489 pSMB->TotalDataCount = 0;
5490 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5 5491 /* BB find exact max SMB PDU from sess structure BB */
e529614a 5492 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
1da177e4
LT
5493 pSMB->MaxSetupCount = 0;
5494 pSMB->Reserved = 0;
5495 pSMB->Flags = 0;
5496 pSMB->Timeout = 0;
5497 pSMB->Reserved2 = 0;
5498 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5499 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
5500 pSMB->DataCount = 0;
5501 pSMB->DataOffset = 0;
5502 pSMB->SetupCount = 1;
5503 pSMB->Reserved3 = 0;
5504 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5505 byte_count = params + 1 /* pad */ ;
5506 pSMB->TotalParameterCount = cpu_to_le16(params);
5507 pSMB->ParameterCount = pSMB->TotalParameterCount;
5508 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5509 pSMB->Reserved4 = 0;
5510 pSMB->hdr.smb_buf_length += byte_count;
5511 pSMB->ByteCount = cpu_to_le16(byte_count);
5512
5513 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5514 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5515 if (rc) {
b6b38f70 5516 cFYI(1, "Send error in QueryAllEAs = %d", rc);
f0d3868b
JL
5517 goto QAllEAsOut;
5518 }
1da177e4 5519
f0d3868b
JL
5520
5521 /* BB also check enough total bytes returned */
5522 /* BB we need to improve the validity checking
5523 of these trans2 responses */
5524
5525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5526 if (rc || (pSMBr->ByteCount < 4)) {
5527 rc = -EIO; /* bad smb */
5528 goto QAllEAsOut;
5529 }
5530
5531 /* check that length of list is not more than bcc */
5532 /* check that each entry does not go beyond length
5533 of list */
5534 /* check that each element of each entry does not
5535 go beyond end of list */
5536 /* validate_trans2_offsets() */
5537 /* BB check if start of smb + data_offset > &bcc+ bcc */
5538
5539 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5540 ea_response_data = (struct fealist *)
5541 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5542
6e462b9f 5543 list_len = le32_to_cpu(ea_response_data->list_len);
b6b38f70 5544 cFYI(1, "ea length %d", list_len);
6e462b9f 5545 if (list_len <= 8) {
b6b38f70 5546 cFYI(1, "empty EA list returned from server");
f0d3868b
JL
5547 goto QAllEAsOut;
5548 }
5549
0cd126b5
JL
5550 /* make sure list_len doesn't go past end of SMB */
5551 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5552 if ((char *)ea_response_data + list_len > end_of_smb) {
b6b38f70 5553 cFYI(1, "EA list appears to go beyond SMB");
0cd126b5
JL
5554 rc = -EIO;
5555 goto QAllEAsOut;
5556 }
5557
f0d3868b 5558 /* account for ea list len */
6e462b9f 5559 list_len -= 4;
f0d3868b
JL
5560 temp_fea = ea_response_data->list;
5561 temp_ptr = (char *)temp_fea;
6e462b9f 5562 while (list_len > 0) {
122ca007 5563 unsigned int name_len;
f0d3868b 5564 __u16 value_len;
0cd126b5 5565
6e462b9f 5566 list_len -= 4;
f0d3868b 5567 temp_ptr += 4;
0cd126b5
JL
5568 /* make sure we can read name_len and value_len */
5569 if (list_len < 0) {
b6b38f70 5570 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
5571 rc = -EIO;
5572 goto QAllEAsOut;
5573 }
5574
5575 name_len = temp_fea->name_len;
5576 value_len = le16_to_cpu(temp_fea->value_len);
5577 list_len -= name_len + 1 + value_len;
5578 if (list_len < 0) {
b6b38f70 5579 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
5580 rc = -EIO;
5581 goto QAllEAsOut;
5582 }
5583
31c0519f
JL
5584 if (ea_name) {
5585 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5586 temp_ptr += name_len + 1;
5587 rc = value_len;
5588 if (buf_size == 0)
5589 goto QAllEAsOut;
5590 if ((size_t)value_len > buf_size) {
5591 rc = -ERANGE;
5592 goto QAllEAsOut;
5593 }
5594 memcpy(EAData, temp_ptr, value_len);
5595 goto QAllEAsOut;
5596 }
f0d3868b 5597 } else {
31c0519f
JL
5598 /* account for prefix user. and trailing null */
5599 rc += (5 + 1 + name_len);
5600 if (rc < (int) buf_size) {
5601 memcpy(EAData, "user.", 5);
5602 EAData += 5;
5603 memcpy(EAData, temp_ptr, name_len);
5604 EAData += name_len;
5605 /* null terminate name */
5606 *EAData = 0;
5607 ++EAData;
5608 } else if (buf_size == 0) {
5609 /* skip copy - calc size only */
5610 } else {
5611 /* stop before overrun buffer */
5612 rc = -ERANGE;
5613 break;
5614 }
1da177e4 5615 }
0cd126b5 5616 temp_ptr += name_len + 1 + value_len;
f0d3868b 5617 temp_fea = (struct fea *)temp_ptr;
1da177e4 5618 }
f0d3868b 5619
31c0519f
JL
5620 /* didn't find the named attribute */
5621 if (ea_name)
5622 rc = -ENODATA;
5623
f0d3868b 5624QAllEAsOut:
0d817bc0 5625 cifs_buf_release(pSMB);
1da177e4
LT
5626 if (rc == -EAGAIN)
5627 goto QAllEAsRetry;
5628
5629 return (ssize_t)rc;
5630}
5631
1da177e4
LT
5632int
5633CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
50c2f753
SF
5634 const char *ea_name, const void *ea_value,
5635 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5636 int remap)
1da177e4
LT
5637{
5638 struct smb_com_transaction2_spi_req *pSMB = NULL;
5639 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5640 struct fealist *parm_data;
5641 int name_len;
5642 int rc = 0;
5643 int bytes_returned = 0;
5644 __u16 params, param_offset, byte_count, offset, count;
5645
b6b38f70 5646 cFYI(1, "In SetEA");
1da177e4
LT
5647SetEARetry:
5648 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5649 (void **) &pSMBr);
5650 if (rc)
5651 return rc;
5652
5653 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5654 name_len =
50c2f753 5655 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
737b758c 5656 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5657 name_len++; /* trailing null */
5658 name_len *= 2;
50c2f753 5659 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5660 name_len = strnlen(fileName, PATH_MAX);
5661 name_len++; /* trailing null */
5662 strncpy(pSMB->FileName, fileName, name_len);
5663 }
5664
5665 params = 6 + name_len;
5666
5667 /* done calculating parms using name_len of file name,
5668 now use name_len to calculate length of ea name
5669 we are going to create in the inode xattrs */
790fe579 5670 if (ea_name == NULL)
1da177e4
LT
5671 name_len = 0;
5672 else
50c2f753 5673 name_len = strnlen(ea_name, 255);
1da177e4 5674
dae5dbdb 5675 count = sizeof(*parm_data) + ea_value_len + name_len;
1da177e4 5676 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5677 /* BB find max SMB PDU from sess */
5678 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5679 pSMB->MaxSetupCount = 0;
5680 pSMB->Reserved = 0;
5681 pSMB->Flags = 0;
5682 pSMB->Timeout = 0;
5683 pSMB->Reserved2 = 0;
5684 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5685 InformationLevel) - 4;
1da177e4
LT
5686 offset = param_offset + params;
5687 pSMB->InformationLevel =
5688 cpu_to_le16(SMB_SET_FILE_EA);
5689
5690 parm_data =
5691 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5692 offset);
5693 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5694 pSMB->DataOffset = cpu_to_le16(offset);
5695 pSMB->SetupCount = 1;
5696 pSMB->Reserved3 = 0;
5697 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5698 byte_count = 3 /* pad */ + params + count;
5699 pSMB->DataCount = cpu_to_le16(count);
5700 parm_data->list_len = cpu_to_le32(count);
5701 parm_data->list[0].EA_flags = 0;
5702 /* we checked above that name len is less than 255 */
53b3531b 5703 parm_data->list[0].name_len = (__u8)name_len;
1da177e4 5704 /* EA names are always ASCII */
790fe579 5705 if (ea_name)
50c2f753 5706 strncpy(parm_data->list[0].name, ea_name, name_len);
1da177e4
LT
5707 parm_data->list[0].name[name_len] = 0;
5708 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5709 /* caller ensures that ea_value_len is less than 64K but
5710 we need to ensure that it fits within the smb */
5711
50c2f753
SF
5712 /*BB add length check to see if it would fit in
5713 negotiated SMB buffer size BB */
790fe579
SF
5714 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5715 if (ea_value_len)
50c2f753
SF
5716 memcpy(parm_data->list[0].name+name_len+1,
5717 ea_value, ea_value_len);
1da177e4
LT
5718
5719 pSMB->TotalDataCount = pSMB->DataCount;
5720 pSMB->ParameterCount = cpu_to_le16(params);
5721 pSMB->TotalParameterCount = pSMB->ParameterCount;
5722 pSMB->Reserved4 = 0;
5723 pSMB->hdr.smb_buf_length += byte_count;
5724 pSMB->ByteCount = cpu_to_le16(byte_count);
5725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5727 if (rc)
b6b38f70 5728 cFYI(1, "SetPathInfo (EA) returned %d", rc);
1da177e4
LT
5729
5730 cifs_buf_release(pSMB);
5731
5732 if (rc == -EAGAIN)
5733 goto SetEARetry;
5734
5735 return rc;
5736}
5737
5738#endif