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