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