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