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