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