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