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