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