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