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