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