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