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