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