cifssmb.c 190.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/cifssmb.c
 *
4
 *   Copyright (C) International Business Machines  Corp., 2002,2010
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   Contains the routines for constructing the SMB PDUs themselves
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
 /* These are mostly routines that operate on a pathname, or on a tree id     */
 /* (mounted volume), but there are eight handle based routines which must be */
27 28
 /* treated slightly differently for reconnection purposes since we never     */
 /* want to reuse a stale file handle and only the caller knows the file info */
L
Linus Torvalds 已提交
29 30 31 32

#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/vfs.h>
33
#include <linux/slab.h>
L
Linus Torvalds 已提交
34
#include <linux/posix_acl_xattr.h>
J
Jeff Layton 已提交
35
#include <linux/pagemap.h>
J
Jeff Layton 已提交
36 37
#include <linux/swap.h>
#include <linux/task_io_accounting_ops.h>
38
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
39 40
#include "cifspdu.h"
#include "cifsglob.h"
41
#include "cifsacl.h"
L
Linus Torvalds 已提交
42 43 44
#include "cifsproto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
J
Jeff Layton 已提交
45
#include "fscache.h"
46
#include "smbdirect.h"
L
Linus Torvalds 已提交
47 48 49 50 51 52

#ifdef CONFIG_CIFS_POSIX
static struct {
	int index;
	char *name;
} protocols[] = {
53 54
#ifdef CONFIG_CIFS_WEAK_PW_HASH
	{LANMAN_PROT, "\2LM1.2X002"},
55
	{LANMAN2_PROT, "\2LANMAN2.1"},
56
#endif /* weak password hashing for legacy clients */
57
	{CIFS_PROT, "\2NT LM 0.12"},
58
	{POSIX_PROT, "\2POSIX 2"},
L
Linus Torvalds 已提交
59 60 61 62 63 64 65
	{BAD_PROT, "\2"}
};
#else
static struct {
	int index;
	char *name;
} protocols[] = {
66 67
#ifdef CONFIG_CIFS_WEAK_PW_HASH
	{LANMAN_PROT, "\2LM1.2X002"},
68
	{LANMAN2_PROT, "\2LANMAN2.1"},
69
#endif /* weak password hashing for legacy clients */
S
Steve French 已提交
70
	{CIFS_PROT, "\2NT LM 0.12"},
L
Linus Torvalds 已提交
71 72 73 74
	{BAD_PROT, "\2"}
};
#endif

75 76 77
/* define the number of elements in the cifs dialect array */
#ifdef CONFIG_CIFS_POSIX
#ifdef CONFIG_CIFS_WEAK_PW_HASH
78
#define CIFS_NUM_PROT 4
79 80 81 82 83
#else
#define CIFS_NUM_PROT 2
#endif /* CIFS_WEAK_PW_HASH */
#else /* not posix */
#ifdef CONFIG_CIFS_WEAK_PW_HASH
84
#define CIFS_NUM_PROT 3
85 86 87 88 89
#else
#define CIFS_NUM_PROT 1
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
#endif /* CIFS_POSIX */

90 91 92 93 94 95
/*
 * Mark as invalid, all open files on tree connections since they
 * were closed when session to server was lost.
 */
void
cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
L
Linus Torvalds 已提交
96 97
{
	struct cifsFileInfo *open_file = NULL;
S
Steve French 已提交
98 99
	struct list_head *tmp;
	struct list_head *tmp1;
L
Linus Torvalds 已提交
100

101
	/* list all files open on tree connection and mark them invalid */
102
	spin_lock(&tcon->open_file_lock);
103
	list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
S
Steve French 已提交
104
		open_file = list_entry(tmp, struct cifsFileInfo, tlist);
105
		open_file->invalidHandle = true;
106
		open_file->oplock_break_cancelled = true;
L
Linus Torvalds 已提交
107
	}
108
	spin_unlock(&tcon->open_file_lock);
109 110 111 112
	/*
	 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
	 * to this tcon.
	 */
L
Linus Torvalds 已提交
113 114
}

115 116
/* reconnect the socket, tcon, and smb session if needed */
static int
117
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
118
{
119
	int rc;
120
	struct cifs_ses *ses;
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	struct TCP_Server_Info *server;
	struct nls_table *nls_codepage;

	/*
	 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
	 * tcp and smb session status done differently for those three - in the
	 * calling routine
	 */
	if (!tcon)
		return 0;

	ses = tcon->ses;
	server = ses->server;

	/*
	 * only tree disconnect, open, and write, (and ulogoff which does not
	 * have tcon) are allowed as we start force umount
	 */
	if (tcon->tidStatus == CifsExiting) {
		if (smb_command != SMB_COM_WRITE_ANDX &&
		    smb_command != SMB_COM_OPEN_ANDX &&
		    smb_command != SMB_COM_TREE_DISCONNECT) {
143 144
			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
				 smb_command);
145 146 147 148 149 150 151 152 153 154
			return -ENODEV;
		}
	}

	/*
	 * Give demultiplex thread up to 10 seconds to reconnect, should be
	 * greater than cifs socket timeout which is 7 seconds
	 */
	while (server->tcpStatus == CifsNeedReconnect) {
		wait_event_interruptible_timeout(server->response_q,
155
			(server->tcpStatus != CifsNeedReconnect), 10 * HZ);
156

157
		/* are we still trying to reconnect? */
158 159 160 161 162 163 164 165
		if (server->tcpStatus != CifsNeedReconnect)
			break;

		/*
		 * on "soft" mounts we wait once. Hard mounts keep
		 * retrying until process is killed or server comes
		 * back on-line
		 */
166
		if (!tcon->retry) {
167
			cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
168 169 170 171 172 173 174 175 176 177 178 179 180
			return -EHOSTDOWN;
		}
	}

	if (!ses->need_reconnect && !tcon->need_reconnect)
		return 0;

	nls_codepage = load_nls_default();

	/*
	 * need to prevent multiple threads trying to simultaneously
	 * reconnect the same SMB session
	 */
181
	mutex_lock(&ses->session_mutex);
182 183 184 185 186 187 188 189 190 191 192 193

	/*
	 * Recheck after acquire mutex. If another thread is negotiating
	 * and the server never sends an answer the socket will be closed
	 * and tcpStatus set to reconnect.
	 */
	if (server->tcpStatus == CifsNeedReconnect) {
		rc = -EHOSTDOWN;
		mutex_unlock(&ses->session_mutex);
		goto out;
	}

194 195
	rc = cifs_negotiate_protocol(0, ses);
	if (rc == 0 && ses->need_reconnect)
196 197 198 199
		rc = cifs_setup_session(0, ses, nls_codepage);

	/* do we need to reconnect tcon? */
	if (rc || !tcon->need_reconnect) {
200
		mutex_unlock(&ses->session_mutex);
201 202 203
		goto out;
	}

204
	cifs_mark_open_files_invalid(tcon);
205
	rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
206
	mutex_unlock(&ses->session_mutex);
207
	cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
208

209 210
	if (rc) {
		printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
211
		goto out;
212
	}
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

	atomic_inc(&tconInfoReconnectCount);

	/* tell server Unix caps we support */
	if (ses->capabilities & CAP_UNIX)
		reset_cifs_unix_caps(0, tcon, NULL, NULL);

	/*
	 * Removed call to reopen open files here. It is safer (and faster) to
	 * reopen files one at a time as needed in read and write.
	 *
	 * FIXME: what about file locks? don't we need to reclaim them ASAP?
	 */

out:
	/*
	 * Check if handle based operation so we know whether we can continue
	 * or not without returning to caller to reset file handle
	 */
	switch (smb_command) {
	case SMB_COM_READ_ANDX:
	case SMB_COM_WRITE_ANDX:
	case SMB_COM_CLOSE:
	case SMB_COM_FIND_CLOSE2:
	case SMB_COM_LOCKING_ANDX:
		rc = -EAGAIN;
	}

	unload_nls(nls_codepage);
	return rc;
}

S
Steve French 已提交
245 246 247
/* Allocate and return pointer to an SMB request buffer, and set basic
   SMB information in the SMB header.  If the return code is zero, this
   function must have filled in request_buf pointer */
L
Linus Torvalds 已提交
248
static int
249
small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
S
Steve French 已提交
250
		void **request_buf)
L
Linus Torvalds 已提交
251
{
252
	int rc;
L
Linus Torvalds 已提交
253

254
	rc = cifs_reconnect_tcon(tcon, smb_command);
S
Steve French 已提交
255
	if (rc)
L
Linus Torvalds 已提交
256 257 258 259 260 261 262 263
		return rc;

	*request_buf = cifs_small_buf_get();
	if (*request_buf == NULL) {
		/* BB should we add a retry in here if not a writepage? */
		return -ENOMEM;
	}

264
	header_assemble((struct smb_hdr *) *request_buf, smb_command,
265
			tcon, wct);
L
Linus Torvalds 已提交
266

S
Steve French 已提交
267 268
	if (tcon != NULL)
		cifs_stats_inc(&tcon->num_smbs_sent);
269

270
	return 0;
271 272
}

273
int
274
small_smb_init_no_tc(const int smb_command, const int wct,
275
		     struct cifs_ses *ses, void **request_buf)
276 277
{
	int rc;
278
	struct smb_hdr *buffer;
279

280
	rc = small_smb_init(smb_command, wct, NULL, request_buf);
S
Steve French 已提交
281
	if (rc)
282 283
		return rc;

284
	buffer = (struct smb_hdr *)*request_buf;
285
	buffer->Mid = get_next_mid(ses->server);
286 287
	if (ses->capabilities & CAP_UNICODE)
		buffer->Flags2 |= SMBFLG2_UNICODE;
288
	if (ses->capabilities & CAP_STATUS32)
289 290 291 292
		buffer->Flags2 |= SMBFLG2_ERR_STATUS;

	/* uid, tid can stay at zero as set in header assemble */

293
	/* BB add support for turning on the signing when
294 295 296 297
	this function is used after 1st of session setup requests */

	return rc;
}
L
Linus Torvalds 已提交
298 299 300

/* If the return code is zero, this function must fill in request_buf pointer */
static int
301
__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
302
			void **request_buf, void **response_buf)
L
Linus Torvalds 已提交
303 304 305 306 307 308 309 310 311 312
{
	*request_buf = cifs_buf_get();
	if (*request_buf == NULL) {
		/* BB should we add a retry in here if not a writepage? */
		return -ENOMEM;
	}
    /* Although the original thought was we needed the response buf for  */
    /* potential retries of smb operations it turns out we can determine */
    /* from the mid flags when the request buffer can be resent without  */
    /* having to use a second distinct buffer for the response */
S
Steve French 已提交
313
	if (response_buf)
314
		*response_buf = *request_buf;
L
Linus Torvalds 已提交
315 316

	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
S
Steve French 已提交
317
			wct);
L
Linus Torvalds 已提交
318

S
Steve French 已提交
319 320
	if (tcon != NULL)
		cifs_stats_inc(&tcon->num_smbs_sent);
321

322 323 324 325 326
	return 0;
}

/* If the return code is zero, this function must fill in request_buf pointer */
static int
327
smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
328 329 330 331 332 333 334 335 336 337 338 339
	 void **request_buf, void **response_buf)
{
	int rc;

	rc = cifs_reconnect_tcon(tcon, smb_command);
	if (rc)
		return rc;

	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
}

static int
340
smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
341 342 343 344 345 346
			void **request_buf, void **response_buf)
{
	if (tcon->ses->need_reconnect || tcon->need_reconnect)
		return -EHOSTDOWN;

	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
L
Linus Torvalds 已提交
347 348
}

349
static int validate_t2(struct smb_t2_rsp *pSMB)
L
Linus Torvalds 已提交
350
{
351 352 353 354 355
	unsigned int total_size;

	/* check for plausible wct */
	if (pSMB->hdr.WordCount < 10)
		goto vt2_err;
L
Linus Torvalds 已提交
356 357

	/* check for parm and data offset going beyond end of smb */
358 359 360 361 362 363 364 365
	if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
	    get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
		goto vt2_err;

	total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
	if (total_size >= 512)
		goto vt2_err;

J
Jeff Layton 已提交
366 367 368
	/* check that bcc is at least as big as parms + data, and that it is
	 * less than negotiated smb buffer
	 */
369 370 371 372 373 374 375
	total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
	if (total_size > get_bcc(&pSMB->hdr) ||
	    total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
		goto vt2_err;

	return 0;
vt2_err:
376
	cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
L
Linus Torvalds 已提交
377
		sizeof(struct smb_t2_rsp) + 16);
378
	return -EINVAL;
L
Linus Torvalds 已提交
379
}
380

381
static int
382
decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
383 384 385 386
{
	int	rc = 0;
	u16	count;
	char	*guid = pSMBr->u.extended_response.GUID;
387
	struct TCP_Server_Info *server = ses->server;
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405

	count = get_bcc(&pSMBr->hdr);
	if (count < SMB1_CLIENT_GUID_SIZE)
		return -EIO;

	spin_lock(&cifs_tcp_ses_lock);
	if (server->srv_count > 1) {
		spin_unlock(&cifs_tcp_ses_lock);
		if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
			cifs_dbg(FYI, "server UID changed\n");
			memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
		}
	} else {
		spin_unlock(&cifs_tcp_ses_lock);
		memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
	}

	if (count == SMB1_CLIENT_GUID_SIZE) {
406
		server->sec_ntlmssp = true;
407 408 409 410 411 412 413 414 415 416 417
	} else {
		count -= SMB1_CLIENT_GUID_SIZE;
		rc = decode_negTokenInit(
			pSMBr->u.extended_response.SecurityBlob, count, server);
		if (rc != 1)
			return -EINVAL;
	}

	return 0;
}

418
int
419
cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
420
{
421 422
	bool srv_sign_required = server->sec_mode & server->vals->signing_required;
	bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
	bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;

	/*
	 * Is signing required by mnt options? If not then check
	 * global_secflags to see if it is there.
	 */
	if (!mnt_sign_required)
		mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
						CIFSSEC_MUST_SIGN);

	/*
	 * If signing is required then it's automatically enabled too,
	 * otherwise, check to see if the secflags allow it.
	 */
	mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
				(global_secflags & CIFSSEC_MAY_SIGN);

	/* If server requires signing, does client allow it? */
	if (srv_sign_required) {
		if (!mnt_sign_enabled) {
			cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
			return -ENOTSUPP;
445
		}
446 447 448 449 450 451 452 453 454 455
		server->sign = true;
	}

	/* If client requires signing, does server allow it? */
	if (mnt_sign_required) {
		if (!srv_sign_enabled) {
			cifs_dbg(VFS, "Server does not support signing!");
			return -ENOTSUPP;
		}
		server->sign = true;
456 457
	}

458 459 460
	if (cifs_rdma_enabled(server) && server->sign)
		cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled");

461 462 463
	return 0;
}

464 465
#ifdef CONFIG_CIFS_WEAK_PW_HASH
static int
466
decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
{
	__s16 tmp;
	struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;

	if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
		return -EOPNOTSUPP;

	server->sec_mode = le16_to_cpu(rsp->SecurityMode);
	server->maxReq = min_t(unsigned int,
			       le16_to_cpu(rsp->MaxMpxCount),
			       cifs_max_pending);
	set_credits(server, server->maxReq);
	server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
	/* even though we do not use raw we might as well set this
	accurately, in case we ever find a need for it */
	if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
		server->max_rw = 0xFF00;
		server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
	} else {
		server->max_rw = 0;/* do not need to use raw anyway */
		server->capabilities = CAP_MPX_MODE;
	}
	tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
	if (tmp == -1) {
		/* OS/2 often does not set timezone therefore
		 * we must use server time to calc time zone.
		 * Could deviate slightly from the right zone.
		 * Smallest defined timezone difference is 15 minutes
		 * (i.e. Nepal).  Rounding up/down is done to match
		 * this requirement.
		 */
		int val, seconds, remain, result;
499 500
		struct timespec ts;
		unsigned long utc = ktime_get_real_seconds();
501 502 503
		ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
				    rsp->SrvTime.Time, 0);
		cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
504 505 506
			 (int)ts.tv_sec, (int)utc,
			 (int)(utc - ts.tv_sec));
		val = (int)(utc - ts.tv_sec);
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
		seconds = abs(val);
		result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
		remain = seconds % MIN_TZ_ADJ;
		if (remain >= (MIN_TZ_ADJ / 2))
			result += MIN_TZ_ADJ;
		if (val < 0)
			result = -result;
		server->timeAdj = result;
	} else {
		server->timeAdj = (int)tmp;
		server->timeAdj *= 60; /* also in seconds */
	}
	cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);


	/* BB get server time for time conversions and add
	code to use it and timezone since this is not UTC */

	if (rsp->EncryptionKeyLength ==
			cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
		memcpy(server->cryptkey, rsp->EncryptionKey,
			CIFS_CRYPTO_KEY_SIZE);
	} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
		return -EIO; /* need cryptkey unless plain text */
	}

	cifs_dbg(FYI, "LANMAN negotiated\n");
	return 0;
}
#else
static inline int
538
decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
539 540 541 542 543 544
{
	cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
	return -EOPNOTSUPP;
}
#endif

545
static bool
546
should_set_ext_sec_flag(enum securityEnum sectype)
547
{
548 549 550
	switch (sectype) {
	case RawNTLMSSP:
	case Kerberos:
551
		return true;
552 553 554 555 556 557 558 559
	case Unspecified:
		if (global_secflags &
		    (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
			return true;
		/* Fallthrough */
	default:
		return false;
	}
560 561
}

L
Linus Torvalds 已提交
562
int
563
CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
L
Linus Torvalds 已提交
564 565 566 567 568
{
	NEGOTIATE_REQ *pSMB;
	NEGOTIATE_RSP *pSMBr;
	int rc = 0;
	int bytes_returned;
569
	int i;
570
	struct TCP_Server_Info *server = ses->server;
L
Linus Torvalds 已提交
571 572
	u16 count;

573 574 575
	if (!server) {
		WARN(1, "%s: server is NULL!\n", __func__);
		return -EIO;
L
Linus Torvalds 已提交
576
	}
577

L
Linus Torvalds 已提交
578 579 580 581
	rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
		      (void **) &pSMB, (void **) &pSMBr);
	if (rc)
		return rc;
582

583
	pSMB->hdr.Mid = get_next_mid(server);
584
	pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
585

586
	if (should_set_ext_sec_flag(ses->sectype)) {
587
		cifs_dbg(FYI, "Requesting extended security.");
588 589
		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
	}
590

591
	count = 0;
592
	for (i = 0; i < CIFS_NUM_PROT; i++) {
593 594 595 596
		strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
		count += strlen(protocols[i].name) + 1;
		/* null at end of source and target buffers anyway */
	}
597
	inc_rfc1001_len(pSMB, count);
L
Linus Torvalds 已提交
598 599 600 601
	pSMB->ByteCount = cpu_to_le16(count);

	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
602
	if (rc != 0)
603 604
		goto neg_err_exit;

605
	server->dialect = le16_to_cpu(pSMBr->DialectIndex);
606
	cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
607
	/* Check wct = 1 error case */
608
	if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
609
		/* core returns wct = 1, but we do not ask for core - otherwise
610
		small wct just comes when dialect index is -1 indicating we
611 612 613
		could not negotiate a common dialect */
		rc = -EOPNOTSUPP;
		goto neg_err_exit;
S
Steve French 已提交
614
	} else if (pSMBr->hdr.WordCount == 13) {
615
		server->negflavor = CIFS_NEGFLAVOR_LANMAN;
616
		rc = decode_lanman_negprot_rsp(server, pSMBr);
617
		goto signing_check;
S
Steve French 已提交
618
	} else if (pSMBr->hdr.WordCount != 17) {
619 620 621 622
		/* unknown wct */
		rc = -EOPNOTSUPP;
		goto neg_err_exit;
	}
623 624
	/* else wct == 17, NTLM or better */

625 626
	server->sec_mode = pSMBr->SecurityMode;
	if ((server->sec_mode & SECMODE_USER) == 0)
627
		cifs_dbg(FYI, "share mode security\n");
628

629 630
	/* one byte, so no need to convert this or EncryptionKeyLen from
	   little endian */
631 632
	server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
			       cifs_max_pending);
633
	set_credits(server, server->maxReq);
634
	/* probably no need to store and check maxvcs */
635
	server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
636
	server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
637
	cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
638
	server->capabilities = le32_to_cpu(pSMBr->Capabilities);
639 640
	server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
	server->timeAdj *= 60;
641

642 643
	if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
644
		memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
645
		       CIFS_CRYPTO_KEY_SIZE);
646 647
	} else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
			server->capabilities & CAP_EXTENDED_SECURITY) {
648
		server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
649
		rc = decode_ext_sec_blob(ses, pSMBr);
650
	} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
651
		rc = -EIO; /* no crypt key only if plain text pwd */
652 653
	} else {
		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
654
		server->capabilities &= ~CAP_EXTENDED_SECURITY;
655
	}
656 657

signing_check:
658
	if (!rc)
659
		rc = cifs_enable_signing(server, ses->sign);
660
neg_err_exit:
661
	cifs_buf_release(pSMB);
662

663
	cifs_dbg(FYI, "negprot rc %d\n", rc);
L
Linus Torvalds 已提交
664 665 666 667
	return rc;
}

int
668
CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
L
Linus Torvalds 已提交
669 670 671 672
{
	struct smb_hdr *smb_buffer;
	int rc = 0;

673
	cifs_dbg(FYI, "In tree disconnect\n");
L
Linus Torvalds 已提交
674

675 676 677
	/* BB: do we need to check this? These should never be NULL. */
	if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
		return -EIO;
L
Linus Torvalds 已提交
678

679 680 681 682 683 684
	/*
	 * No need to return error on this operation if tid invalidated and
	 * closed on server already e.g. due to tcp session crashing. Also,
	 * the tcon is no longer on the list, so no need to take lock before
	 * checking this.
	 */
685
	if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
686
		return 0;
L
Linus Torvalds 已提交
687

688
	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
689
			    (void **)&smb_buffer);
690
	if (rc)
L
Linus Torvalds 已提交
691
		return rc;
692

693
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
694
	cifs_small_buf_release(smb_buffer);
L
Linus Torvalds 已提交
695
	if (rc)
696
		cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
L
Linus Torvalds 已提交
697

698
	/* No need to return error on this operation if tid invalidated and
699
	   closed on server already e.g. due to tcp session crashing */
L
Linus Torvalds 已提交
700 701 702 703 704 705
	if (rc == -EAGAIN)
		rc = 0;

	return rc;
}

706 707 708 709 710 711 712 713 714 715 716 717 718
/*
 * This is a no-op for now. We're not really interested in the reply, but
 * rather in the fact that the server sent one and that server->lstrp
 * gets updated.
 *
 * FIXME: maybe we should consider checking that the reply matches request?
 */
static void
cifs_echo_callback(struct mid_q_entry *mid)
{
	struct TCP_Server_Info *server = mid->callback_data;

	DeleteMidQEntry(mid);
719
	add_credits(server, 1, CIFS_ECHO_OP);
720 721 722 723 724 725 726
}

int
CIFSSMBEcho(struct TCP_Server_Info *server)
{
	ECHO_REQ *smb;
	int rc = 0;
727 728 729
	struct kvec iov[2];
	struct smb_rqst rqst = { .rq_iov = iov,
				 .rq_nvec = 2 };
730

731
	cifs_dbg(FYI, "In echo request\n");
732 733 734 735 736

	rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
	if (rc)
		return rc;

737 738 739
	if (server->capabilities & CAP_UNICODE)
		smb->hdr.Flags2 |= SMBFLG2_UNICODE;

740
	/* set up echo request */
S
Steve French 已提交
741
	smb->hdr.Tid = 0xffff;
742 743
	smb->hdr.WordCount = 1;
	put_unaligned_le16(1, &smb->EchoCount);
744
	put_bcc(1, &smb->hdr);
745
	smb->Data[0] = 'a';
746
	inc_rfc1001_len(smb, 3);
747 748 749 750 751

	iov[0].iov_len = 4;
	iov[0].iov_base = smb;
	iov[1].iov_len = get_rfc1002_length(smb);
	iov[1].iov_base = (char *)smb + 4;
752

P
Pavel Shilovsky 已提交
753
	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
754
			     server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
755
	if (rc)
756
		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
757 758 759 760 761 762

	cifs_small_buf_release(smb);

	return rc;
}

L
Linus Torvalds 已提交
763
int
764
CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
L
Linus Torvalds 已提交
765 766 767 768
{
	LOGOFF_ANDX_REQ *pSMB;
	int rc = 0;

769
	cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
S
Steve French 已提交
770

771 772 773 774 775 776
	/*
	 * BB: do we need to check validity of ses and server? They should
	 * always be valid since we have an active reference. If not, that
	 * should probably be a BUG()
	 */
	if (!ses || !ses->server)
S
Steve French 已提交
777 778
		return -EIO;

779
	mutex_lock(&ses->session_mutex);
S
Steve French 已提交
780 781 782
	if (ses->need_reconnect)
		goto session_already_dead; /* no need to send SMBlogoff if uid
					      already closed due to reconnect */
L
Linus Torvalds 已提交
783 784
	rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
	if (rc) {
785
		mutex_unlock(&ses->session_mutex);
L
Linus Torvalds 已提交
786 787 788
		return rc;
	}

789
	pSMB->hdr.Mid = get_next_mid(ses->server);
790

791 792
	if (ses->server->sign)
		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
L
Linus Torvalds 已提交
793 794 795 796

	pSMB->hdr.Uid = ses->Suid;

	pSMB->AndXCommand = 0xFF;
797
	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
798
	cifs_small_buf_release(pSMB);
S
Steve French 已提交
799
session_already_dead:
800
	mutex_unlock(&ses->session_mutex);
L
Linus Torvalds 已提交
801 802

	/* if session dead then we do not need to do ulogoff,
803
		since server closed smb session, no sense reporting
L
Linus Torvalds 已提交
804 805 806 807 808 809
		error */
	if (rc == -EAGAIN)
		rc = 0;
	return rc;
}

810
int
811 812 813
CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
		 const char *fileName, __u16 type,
		 const struct nls_table *nls_codepage, int remap)
814 815 816 817 818 819 820 821 822
{
	TRANSACTION2_SPI_REQ *pSMB = NULL;
	TRANSACTION2_SPI_RSP *pSMBr = NULL;
	struct unlink_psx_rq *pRqD;
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, param_offset, offset, byte_count;

823
	cifs_dbg(FYI, "In POSIX delete\n");
824 825 826 827 828 829 830 831
PsxDelete:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
832 833
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
				       PATH_MAX, nls_codepage, remap);
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
		name_len++;	/* trailing null */
		name_len *= 2;
	} else { /* BB add path length overrun check */
		name_len = strnlen(fileName, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, fileName, name_len);
	}

	params = 6 + name_len;
	pSMB->MaxParameterCount = cpu_to_le16(2);
	pSMB->MaxDataCount = 0; /* BB double check this with jra */
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
				InformationLevel) - 4;
	offset = param_offset + params;

	/* Setup pointer to Request Data (inode type) */
	pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
	pRqD->type = cpu_to_le16(type);
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq);

	pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
	pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
	pSMB->Reserved4 = 0;
870
	inc_rfc1001_len(pSMB, byte_count);
871 872 873
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
S
Steve French 已提交
874
	if (rc)
875
		cifs_dbg(FYI, "Posix delete returned %d\n", rc);
876 877
	cifs_buf_release(pSMB);

878
	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
879 880 881 882 883 884 885

	if (rc == -EAGAIN)
		goto PsxDelete;

	return rc;
}

L
Linus Torvalds 已提交
886
int
887 888
CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
	       struct cifs_sb_info *cifs_sb)
L
Linus Torvalds 已提交
889 890 891 892 893 894
{
	DELETE_FILE_REQ *pSMB = NULL;
	DELETE_FILE_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	int name_len;
895
	int remap = cifs_remap(cifs_sb);
L
Linus Torvalds 已提交
896 897 898 899 900 901 902 903

DelFileRetry:
	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
904 905 906
		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
					      PATH_MAX, cifs_sb->local_nls,
					      remap);
L
Linus Torvalds 已提交
907 908
		name_len++;	/* trailing null */
		name_len *= 2;
909
	} else {		/* BB improve check for buffer overruns BB */
910
		name_len = strnlen(name, PATH_MAX);
L
Linus Torvalds 已提交
911
		name_len++;	/* trailing null */
912
		strncpy(pSMB->fileName, name, name_len);
L
Linus Torvalds 已提交
913 914 915 916
	}
	pSMB->SearchAttributes =
	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
	pSMB->BufferFormat = 0x04;
917
	inc_rfc1001_len(pSMB, name_len + 1);
L
Linus Torvalds 已提交
918 919 920
	pSMB->ByteCount = cpu_to_le16(name_len + 1);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
921
	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
S
Steve French 已提交
922
	if (rc)
923
		cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
L
Linus Torvalds 已提交
924 925 926 927 928 929 930 931 932

	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto DelFileRetry;

	return rc;
}

int
933 934
CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
	     struct cifs_sb_info *cifs_sb)
L
Linus Torvalds 已提交
935 936 937 938 939 940
{
	DELETE_DIRECTORY_REQ *pSMB = NULL;
	DELETE_DIRECTORY_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	int name_len;
941
	int remap = cifs_remap(cifs_sb);
L
Linus Torvalds 已提交
942

943
	cifs_dbg(FYI, "In CIFSSMBRmDir\n");
L
Linus Torvalds 已提交
944 945 946 947 948 949 950
RmDirRetry:
	rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
951 952 953
		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
					      PATH_MAX, cifs_sb->local_nls,
					      remap);
L
Linus Torvalds 已提交
954 955
		name_len++;	/* trailing null */
		name_len *= 2;
956
	} else {		/* BB improve check for buffer overruns BB */
957
		name_len = strnlen(name, PATH_MAX);
L
Linus Torvalds 已提交
958
		name_len++;	/* trailing null */
959
		strncpy(pSMB->DirName, name, name_len);
L
Linus Torvalds 已提交
960 961 962
	}

	pSMB->BufferFormat = 0x04;
963
	inc_rfc1001_len(pSMB, name_len + 1);
L
Linus Torvalds 已提交
964 965 966
	pSMB->ByteCount = cpu_to_le16(name_len + 1);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
967
	cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
S
Steve French 已提交
968
	if (rc)
969
		cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
L
Linus Torvalds 已提交
970 971 972 973 974 975 976 977

	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto RmDirRetry;
	return rc;
}

int
978 979
CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
	     struct cifs_sb_info *cifs_sb)
L
Linus Torvalds 已提交
980 981 982 983 984 985
{
	int rc = 0;
	CREATE_DIRECTORY_REQ *pSMB = NULL;
	CREATE_DIRECTORY_RSP *pSMBr = NULL;
	int bytes_returned;
	int name_len;
986
	int remap = cifs_remap(cifs_sb);
L
Linus Torvalds 已提交
987

988
	cifs_dbg(FYI, "In CIFSSMBMkDir\n");
L
Linus Torvalds 已提交
989 990 991 992 993 994 995
MkDirRetry:
	rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
996
		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
997 998
					      PATH_MAX, cifs_sb->local_nls,
					      remap);
L
Linus Torvalds 已提交
999 1000
		name_len++;	/* trailing null */
		name_len *= 2;
1001
	} else {		/* BB improve check for buffer overruns BB */
L
Linus Torvalds 已提交
1002 1003 1004 1005 1006 1007
		name_len = strnlen(name, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->DirName, name, name_len);
	}

	pSMB->BufferFormat = 0x04;
1008
	inc_rfc1001_len(pSMB, name_len + 1);
L
Linus Torvalds 已提交
1009 1010 1011
	pSMB->ByteCount = cpu_to_le16(name_len + 1);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1012
	cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
S
Steve French 已提交
1013
	if (rc)
1014
		cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
1015

L
Linus Torvalds 已提交
1016 1017 1018 1019 1020 1021
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto MkDirRetry;
	return rc;
}

1022
int
1023 1024 1025 1026 1027
CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
		__u32 posix_flags, __u64 mode, __u16 *netfid,
		FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
		const char *name, const struct nls_table *nls_codepage,
		int remap)
1028 1029 1030 1031 1032 1033 1034
{
	TRANSACTION2_SPI_REQ *pSMB = NULL;
	TRANSACTION2_SPI_RSP *pSMBr = NULL;
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, param_offset, offset, byte_count, count;
S
Steve French 已提交
1035 1036
	OPEN_PSX_REQ *pdata;
	OPEN_PSX_RSP *psx_rsp;
1037

1038
	cifs_dbg(FYI, "In POSIX Create\n");
1039 1040 1041 1042 1043 1044 1045 1046
PsxCreat:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
1047 1048
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
				       PATH_MAX, nls_codepage, remap);
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
		name_len++;	/* trailing null */
		name_len *= 2;
	} else {	/* BB improve the check for buffer overruns BB */
		name_len = strnlen(name, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, name, name_len);
	}

	params = 6 + name_len;
	count = sizeof(OPEN_PSX_REQ);
	pSMB->MaxParameterCount = cpu_to_le16(2);
	pSMB->MaxDataCount = cpu_to_le16(1000);	/* large enough */
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
1067
				InformationLevel) - 4;
1068 1069
	offset = param_offset + params;
	pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1070
	pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
1071
	pdata->Permissions = cpu_to_le64(mode);
1072
	pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
	pdata->OpenFlags =  cpu_to_le32(*pOplock);
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + count;

	pSMB->DataCount = cpu_to_le16(count);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
	pSMB->Reserved4 = 0;
1087
	inc_rfc1001_len(pSMB, byte_count);
1088 1089 1090 1091
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
1092
		cifs_dbg(FYI, "Posix create returned %d\n", rc);
1093 1094 1095
		goto psx_create_err;
	}

1096
	cifs_dbg(FYI, "copying inode info\n");
1097 1098
	rc = validate_t2((struct smb_t2_rsp *)pSMBr);

1099
	if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
1100 1101 1102 1103 1104
		rc = -EIO;	/* bad smb */
		goto psx_create_err;
	}

	/* copy return information to pRetData */
1105
	psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1106
			+ le16_to_cpu(pSMBr->t2.DataOffset));
1107

1108
	*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
S
Steve French 已提交
1109
	if (netfid)
1110 1111 1112
		*netfid = psx_rsp->Fid;   /* cifs fid stays in le */
	/* Let caller know file was created so we can set the mode. */
	/* Do we care about the CreateAction in any other cases? */
S
Steve French 已提交
1113
	if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1114 1115
		*pOplock |= CIFS_CREATE_ACTION;
	/* check to make sure response data is there */
1116 1117
	if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
		pRetData->Type = cpu_to_le32(-1); /* unknown */
1118
		cifs_dbg(NOISY, "unknown type\n");
1119
	} else {
1120
		if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
1121
					+ sizeof(FILE_UNIX_BASIC_INFO)) {
1122
			cifs_dbg(VFS, "Open response data too small\n");
1123
			pRetData->Type = cpu_to_le32(-1);
1124 1125
			goto psx_create_err;
		}
1126
		memcpy((char *) pRetData,
1127
			(char *)psx_rsp + sizeof(OPEN_PSX_RSP),
1128
			sizeof(FILE_UNIX_BASIC_INFO));
1129 1130 1131 1132 1133
	}

psx_create_err:
	cifs_buf_release(pSMB);

1134
	if (posix_flags & SMB_O_DIRECTORY)
1135
		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
1136
	else
1137
		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
1138 1139 1140 1141

	if (rc == -EAGAIN)
		goto PsxCreat;

1142
	return rc;
1143 1144
}

1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
static __u16 convert_disposition(int disposition)
{
	__u16 ofun = 0;

	switch (disposition) {
		case FILE_SUPERSEDE:
			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
			break;
		case FILE_OPEN:
			ofun = SMBOPEN_OAPPEND;
			break;
		case FILE_CREATE:
			ofun = SMBOPEN_OCREATE;
			break;
		case FILE_OPEN_IF:
			ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
			break;
		case FILE_OVERWRITE:
			ofun = SMBOPEN_OTRUNC;
			break;
		case FILE_OVERWRITE_IF:
			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
			break;
		default:
1169
			cifs_dbg(FYI, "unknown disposition %d\n", disposition);
1170 1171 1172 1173 1174
			ofun =  SMBOPEN_OAPPEND; /* regular open */
	}
	return ofun;
}

1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
static int
access_flags_to_smbopen_mode(const int access_flags)
{
	int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);

	if (masked_flags == GENERIC_READ)
		return SMBOPEN_READ;
	else if (masked_flags == GENERIC_WRITE)
		return SMBOPEN_WRITE;

	/* just go for read/write */
	return SMBOPEN_READWRITE;
}

1189
int
1190
SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
1191
	    const char *fileName, const int openDisposition,
S
Steve French 已提交
1192 1193
	    const int access_flags, const int create_options, __u16 *netfid,
	    int *pOplock, FILE_ALL_INFO *pfile_info,
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
	    const struct nls_table *nls_codepage, int remap)
{
	int rc = -EACCES;
	OPENX_REQ *pSMB = NULL;
	OPENX_RSP *pSMBr = NULL;
	int bytes_returned;
	int name_len;
	__u16 count;

OldOpenRetry:
	rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	pSMB->AndXCommand = 0xFF;       /* none */

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		count = 1;      /* account for one byte pad to word boundary */
		name_len =
1214 1215
		   cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
				      fileName, PATH_MAX, nls_codepage, remap);
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
		name_len++;     /* trailing null */
		name_len *= 2;
	} else {                /* BB improve check for buffer overruns BB */
		count = 0;      /* no pad */
		name_len = strnlen(fileName, PATH_MAX);
		name_len++;     /* trailing null */
		strncpy(pSMB->fileName, fileName, name_len);
	}
	if (*pOplock & REQ_OPLOCK)
		pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1226
	else if (*pOplock & REQ_BATCHOPLOCK)
1227
		pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1228

1229
	pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1230
	pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
1231 1232 1233 1234 1235
	pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
	/* set file as system file if special file such
	   as fifo and server expecting SFU style and
	   no Unix extensions */

S
Steve French 已提交
1236 1237
	if (create_options & CREATE_OPTION_SPECIAL)
		pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
S
Steve French 已提交
1238 1239
	else /* BB FIXME BB */
		pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
1240

1241 1242
	if (create_options & CREATE_OPTION_READONLY)
		pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
1243 1244

	/* BB FIXME BB */
1245 1246
/*	pSMB->CreateOptions = cpu_to_le32(create_options &
						 CREATE_OPTIONS_MASK); */
1247
	/* BB FIXME END BB */
1248 1249

	pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
1250
	pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
1251
	count += name_len;
1252
	inc_rfc1001_len(pSMB, count);
1253 1254 1255

	pSMB->ByteCount = cpu_to_le16(count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1256
			(struct smb_hdr *)pSMBr, &bytes_returned, 0);
1257
	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
1258
	if (rc) {
1259
		cifs_dbg(FYI, "Error in Open = %d\n", rc);
1260 1261 1262
	} else {
	/* BB verify if wct == 15 */

1263
/*		*pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
1264 1265 1266 1267 1268

		*netfid = pSMBr->Fid;   /* cifs fid stays in le */
		/* Let caller know file was created so we can set the mode. */
		/* Do we care about the CreateAction in any other cases? */
	/* BB FIXME BB */
S
Steve French 已提交
1269
/*		if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1270 1271 1272
			*pOplock |= CIFS_CREATE_ACTION; */
	/* BB FIXME END */

S
Steve French 已提交
1273
		if (pfile_info) {
1274 1275 1276 1277
			pfile_info->CreationTime = 0; /* BB convert CreateTime*/
			pfile_info->LastAccessTime = 0; /* BB fixme */
			pfile_info->LastWriteTime = 0; /* BB fixme */
			pfile_info->ChangeTime = 0;  /* BB fixme */
1278
			pfile_info->Attributes =
1279
				cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
1280
			/* the file_info buf is endian converted by caller */
1281 1282 1283
			pfile_info->AllocationSize =
				cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
			pfile_info->EndOfFile = pfile_info->AllocationSize;
1284
			pfile_info->NumberOfLinks = cpu_to_le32(1);
1285
			pfile_info->DeletePending = 0;
1286 1287 1288 1289 1290 1291 1292 1293 1294
		}
	}

	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto OldOpenRetry;
	return rc;
}

L
Linus Torvalds 已提交
1295
int
1296 1297
CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
	  FILE_ALL_INFO *buf)
L
Linus Torvalds 已提交
1298 1299
{
	int rc = -EACCES;
P
Pavel Shilovsky 已提交
1300 1301
	OPEN_REQ *req = NULL;
	OPEN_RSP *rsp = NULL;
L
Linus Torvalds 已提交
1302 1303 1304
	int bytes_returned;
	int name_len;
	__u16 count;
1305 1306
	struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
	struct cifs_tcon *tcon = oparms->tcon;
1307
	int remap = cifs_remap(cifs_sb);
1308 1309 1310 1311 1312
	const struct nls_table *nls = cifs_sb->local_nls;
	int create_options = oparms->create_options;
	int desired_access = oparms->desired_access;
	int disposition = oparms->disposition;
	const char *path = oparms->path;
L
Linus Torvalds 已提交
1313 1314

openRetry:
P
Pavel Shilovsky 已提交
1315 1316
	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
		      (void **)&rsp);
L
Linus Torvalds 已提交
1317 1318 1319
	if (rc)
		return rc;

P
Pavel Shilovsky 已提交
1320 1321
	/* no commands go after this */
	req->AndXCommand = 0xFF;
L
Linus Torvalds 已提交
1322

P
Pavel Shilovsky 已提交
1323 1324 1325 1326 1327 1328 1329
	if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
		/* account for one byte pad to word boundary */
		count = 1;
		name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
					      path, PATH_MAX, nls, remap);
		/* trailing null */
		name_len++;
L
Linus Torvalds 已提交
1330
		name_len *= 2;
P
Pavel Shilovsky 已提交
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
		req->NameLength = cpu_to_le16(name_len);
	} else {
		/* BB improve check for buffer overruns BB */
		/* no pad */
		count = 0;
		name_len = strnlen(path, PATH_MAX);
		/* trailing null */
		name_len++;
		req->NameLength = cpu_to_le16(name_len);
		strncpy(req->fileName, path, name_len);
L
Linus Torvalds 已提交
1341
	}
P
Pavel Shilovsky 已提交
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354

	if (*oplock & REQ_OPLOCK)
		req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
	else if (*oplock & REQ_BATCHOPLOCK)
		req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);

	req->DesiredAccess = cpu_to_le32(desired_access);
	req->AllocationSize = 0;

	/*
	 * Set file as system file if special file such as fifo and server
	 * expecting SFU style and no Unix extensions.
	 */
S
Steve French 已提交
1355
	if (create_options & CREATE_OPTION_SPECIAL)
P
Pavel Shilovsky 已提交
1356
		req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1357
	else
P
Pavel Shilovsky 已提交
1358
		req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1359

P
Pavel Shilovsky 已提交
1360 1361 1362 1363
	/*
	 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
	 * sensitive checks for other servers such as Samba.
	 */
L
Linus Torvalds 已提交
1364
	if (tcon->ses->capabilities & CAP_UNIX)
P
Pavel Shilovsky 已提交
1365
		req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
L
Linus Torvalds 已提交
1366

1367
	if (create_options & CREATE_OPTION_READONLY)
P
Pavel Shilovsky 已提交
1368 1369 1370 1371 1372
		req->FileAttributes |= cpu_to_le32(ATTR_READONLY);

	req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
	req->CreateDisposition = cpu_to_le32(disposition);
	req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1373

1374
	/* BB Expirement with various impersonation levels and verify */
P
Pavel Shilovsky 已提交
1375 1376
	req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
	req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
L
Linus Torvalds 已提交
1377 1378

	count += name_len;
P
Pavel Shilovsky 已提交
1379
	inc_rfc1001_len(req, count);
L
Linus Torvalds 已提交
1380

P
Pavel Shilovsky 已提交
1381 1382 1383
	req->ByteCount = cpu_to_le16(count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
			 (struct smb_hdr *)rsp, &bytes_returned, 0);
1384
	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
L
Linus Torvalds 已提交
1385
	if (rc) {
1386
		cifs_dbg(FYI, "Error in Open = %d\n", rc);
P
Pavel Shilovsky 已提交
1387 1388 1389 1390
		cifs_buf_release(req);
		if (rc == -EAGAIN)
			goto openRetry;
		return rc;
L
Linus Torvalds 已提交
1391
	}
1392

P
Pavel Shilovsky 已提交
1393 1394 1395
	/* 1 byte no need to le_to_cpu */
	*oplock = rsp->OplockLevel;
	/* cifs fid stays in le */
1396
	oparms->fid->netfid = rsp->Fid;
P
Pavel Shilovsky 已提交
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413

	/* Let caller know file was created so we can set the mode. */
	/* Do we care about the CreateAction in any other cases? */
	if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
		*oplock |= CIFS_CREATE_ACTION;

	if (buf) {
		/* copy from CreationTime to Attributes */
		memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
		/* the file_info buf is endian converted by caller */
		buf->AllocationSize = rsp->AllocationSize;
		buf->EndOfFile = rsp->EndOfFile;
		buf->NumberOfLinks = cpu_to_le32(1);
		buf->DeletePending = 0;
	}

	cifs_buf_release(req);
L
Linus Torvalds 已提交
1414 1415 1416
	return rc;
}

J
Jeff Layton 已提交
1417 1418 1419 1420
/*
 * Discard any remaining data in the current SMB. To do this, we borrow the
 * current bigbuf.
 */
1421
int
1422
cifs_discard_remaining_data(struct TCP_Server_Info *server)
J
Jeff Layton 已提交
1423
{
1424 1425 1426
	unsigned int rfclen = server->pdu_size;
	int remaining = rfclen + server->vals->header_preamble_size -
		server->total_read;
J
Jeff Layton 已提交
1427 1428 1429 1430 1431 1432

	while (remaining > 0) {
		int length;

		length = cifs_read_from_socket(server, server->bigbuf,
				min_t(unsigned int, remaining,
1433
				    CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
J
Jeff Layton 已提交
1434 1435 1436 1437 1438 1439 1440 1441 1442
		if (length < 0)
			return length;
		server->total_read += length;
		remaining -= length;
	}

	return 0;
}

1443 1444 1445 1446 1447 1448
static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
	int length;
	struct cifs_readdata *rdata = mid->callback_data;

1449
	length = cifs_discard_remaining_data(server);
1450
	dequeue_mid(mid, rdata->result);
1451 1452
	mid->resp_buf = server->smallbuf;
	server->smallbuf = NULL;
1453 1454 1455
	return length;
}

1456
int
J
Jeff Layton 已提交
1457 1458 1459
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
	int length, len;
1460
	unsigned int data_offset, data_len;
J
Jeff Layton 已提交
1461
	struct cifs_readdata *rdata = mid->callback_data;
1462
	char *buf = server->smallbuf;
1463
	unsigned int buflen = server->pdu_size +
1464
		server->vals->header_preamble_size;
1465
	bool use_rdma_mr = false;
J
Jeff Layton 已提交
1466

1467 1468
	cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
		 __func__, mid->mid, rdata->offset, rdata->bytes);
J
Jeff Layton 已提交
1469 1470 1471 1472 1473 1474

	/*
	 * read the rest of READ_RSP header (sans Data array), or whatever we
	 * can if there's not enough data. At this point, we've read down to
	 * the Mid.
	 */
1475
	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
1476
							HEADER_SIZE(server) + 1;
J
Jeff Layton 已提交
1477

1478 1479
	length = cifs_read_from_socket(server,
				       buf + HEADER_SIZE(server) - 1, len);
J
Jeff Layton 已提交
1480 1481 1482 1483
	if (length < 0)
		return length;
	server->total_read += length;

1484 1485 1486 1487 1488 1489 1490
	if (server->ops->is_session_expired &&
	    server->ops->is_session_expired(buf)) {
		cifs_reconnect(server);
		wake_up(&server->response_q);
		return -1;
	}

1491 1492
	if (server->ops->is_status_pending &&
	    server->ops->is_status_pending(buf, server, 0)) {
1493
		cifs_discard_remaining_data(server);
1494 1495 1496
		return -1;
	}

J
Jeff Layton 已提交
1497
	/* Was the SMB read successful? */
1498
	rdata->result = server->ops->map_error(buf, false);
J
Jeff Layton 已提交
1499
	if (rdata->result != 0) {
1500 1501
		cifs_dbg(FYI, "%s: server returned error %d\n",
			 __func__, rdata->result);
J
Jeff Layton 已提交
1502 1503 1504 1505
		return cifs_readv_discard(server, mid);
	}

	/* Is there enough to get to the rest of the READ_RSP header? */
1506
	if (server->total_read < server->vals->read_rsp_size) {
1507 1508 1509
		cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
			 __func__, server->total_read,
			 server->vals->read_rsp_size);
J
Jeff Layton 已提交
1510 1511 1512 1513
		rdata->result = -EIO;
		return cifs_readv_discard(server, mid);
	}

1514 1515
	data_offset = server->ops->read_data_offset(buf) +
		server->vals->header_preamble_size;
J
Jeff Layton 已提交
1516 1517 1518 1519 1520 1521
	if (data_offset < server->total_read) {
		/*
		 * win2k8 sometimes sends an offset of 0 when the read
		 * is beyond the EOF. Treat it as if the data starts just after
		 * the header.
		 */
1522 1523
		cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
			 __func__, data_offset);
J
Jeff Layton 已提交
1524 1525 1526
		data_offset = server->total_read;
	} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
		/* data_offset is beyond the end of smallbuf */
1527 1528
		cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
			 __func__, data_offset);
J
Jeff Layton 已提交
1529 1530 1531 1532
		rdata->result = -EIO;
		return cifs_readv_discard(server, mid);
	}

1533 1534
	cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
		 __func__, server->total_read, data_offset);
J
Jeff Layton 已提交
1535 1536 1537 1538

	len = data_offset - server->total_read;
	if (len > 0) {
		/* read any junk before data into the rest of smallbuf */
1539 1540
		length = cifs_read_from_socket(server,
					       buf + server->total_read, len);
J
Jeff Layton 已提交
1541 1542 1543 1544 1545 1546
		if (length < 0)
			return length;
		server->total_read += length;
	}

	/* set up first iov for signature check */
1547 1548 1549 1550 1551 1552
	rdata->iov[0].iov_base = buf;
	rdata->iov[0].iov_len = 4;
	rdata->iov[1].iov_base = buf + 4;
	rdata->iov[1].iov_len = server->total_read - 4;
	cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
		 rdata->iov[0].iov_base, server->total_read);
J
Jeff Layton 已提交
1553 1554

	/* how much data is in the response? */
1555 1556 1557 1558 1559
#ifdef CONFIG_CIFS_SMB_DIRECT
	use_rdma_mr = rdata->mr;
#endif
	data_len = server->ops->read_data_length(buf, use_rdma_mr);
	if (!use_rdma_mr && (data_offset + data_len > buflen)) {
J
Jeff Layton 已提交
1560 1561 1562 1563 1564
		/* data_len is corrupt -- discard frame */
		rdata->result = -EIO;
		return cifs_readv_discard(server, mid);
	}

1565 1566 1567
	length = rdata->read_into_pages(server, rdata, data_len);
	if (length < 0)
		return length;
J
Jeff Layton 已提交
1568

1569
	server->total_read += length;
J
Jeff Layton 已提交
1570

1571 1572
	cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
		 server->total_read, buflen, data_len);
J
Jeff Layton 已提交
1573 1574

	/* discard anything left over */
1575
	if (server->total_read < buflen)
J
Jeff Layton 已提交
1576 1577 1578
		return cifs_readv_discard(server, mid);

	dequeue_mid(mid, false);
1579 1580
	mid->resp_buf = server->smallbuf;
	server->smallbuf = NULL;
J
Jeff Layton 已提交
1581 1582 1583 1584 1585 1586 1587 1588 1589
	return length;
}

static void
cifs_readv_callback(struct mid_q_entry *mid)
{
	struct cifs_readdata *rdata = mid->callback_data;
	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
	struct TCP_Server_Info *server = tcon->ses->server;
1590 1591
	struct smb_rqst rqst = { .rq_iov = rdata->iov,
				 .rq_nvec = 2,
1592 1593 1594 1595
				 .rq_pages = rdata->pages,
				 .rq_npages = rdata->nr_pages,
				 .rq_pagesz = rdata->pagesz,
				 .rq_tailsz = rdata->tailsz };
J
Jeff Layton 已提交
1596

1597 1598 1599
	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
		 __func__, mid->mid, mid->mid_state, rdata->result,
		 rdata->bytes);
J
Jeff Layton 已提交
1600

1601
	switch (mid->mid_state) {
J
Jeff Layton 已提交
1602 1603
	case MID_RESPONSE_RECEIVED:
		/* result already set, check signature */
1604
		if (server->sign) {
1605 1606
			int rc = 0;

1607
			rc = cifs_verify_signature(&rqst, server,
1608
						  mid->sequence_number);
1609
			if (rc)
1610 1611
				cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
					 rc);
J
Jeff Layton 已提交
1612 1613
		}
		/* FIXME: should this be counted toward the initiating task? */
1614 1615
		task_io_account_read(rdata->got_bytes);
		cifs_stats_bytes_read(tcon, rdata->got_bytes);
J
Jeff Layton 已提交
1616 1617 1618 1619
		break;
	case MID_REQUEST_SUBMITTED:
	case MID_RETRY_NEEDED:
		rdata->result = -EAGAIN;
1620 1621 1622 1623 1624 1625
		if (server->sign && rdata->got_bytes)
			/* reset bytes number since we can not check a sign */
			rdata->got_bytes = 0;
		/* FIXME: should this be counted toward the initiating task? */
		task_io_account_read(rdata->got_bytes);
		cifs_stats_bytes_read(tcon, rdata->got_bytes);
J
Jeff Layton 已提交
1626 1627 1628 1629 1630
		break;
	default:
		rdata->result = -EIO;
	}

J
Jeff Layton 已提交
1631
	queue_work(cifsiod_wq, &rdata->work);
J
Jeff Layton 已提交
1632
	DeleteMidQEntry(mid);
1633
	add_credits(server, 1, 0);
J
Jeff Layton 已提交
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
}

/* cifs_async_readv - send an async write, and set up mid to handle result */
int
cifs_async_readv(struct cifs_readdata *rdata)
{
	int rc;
	READ_REQ *smb = NULL;
	int wct;
	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1644 1645
	struct smb_rqst rqst = { .rq_iov = rdata->iov,
				 .rq_nvec = 2 };
J
Jeff Layton 已提交
1646

1647 1648
	cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
		 __func__, rdata->offset, rdata->bytes);
J
Jeff Layton 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667

	if (tcon->ses->capabilities & CAP_LARGE_FILES)
		wct = 12;
	else {
		wct = 10; /* old style read */
		if ((rdata->offset >> 32) > 0)  {
			/* can not handle this big offset for old */
			return -EIO;
		}
	}

	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
	if (rc)
		return rc;

	smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
	smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));

	smb->AndXCommand = 0xFF;	/* none */
1668
	smb->Fid = rdata->cfile->fid.netfid;
J
Jeff Layton 已提交
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
	smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
	if (wct == 12)
		smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
	smb->Remaining = 0;
	smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
	smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
	if (wct == 12)
		smb->ByteCount = 0;
	else {
		/* old style read */
		struct smb_com_readx_req *smbr =
			(struct smb_com_readx_req *)smb;
		smbr->ByteCount = 0;
	}

	/* 4 for RFC1001 length + 1 for BCC */
1685 1686 1687 1688
	rdata->iov[0].iov_base = smb;
	rdata->iov[0].iov_len = 4;
	rdata->iov[1].iov_base = (char *)smb + 4;
	rdata->iov[1].iov_len = get_rfc1002_length(smb);
J
Jeff Layton 已提交
1689

1690
	kref_get(&rdata->refcount);
1691
	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
P
Pavel Shilovsky 已提交
1692
			     cifs_readv_callback, NULL, rdata, 0);
J
Jeff Layton 已提交
1693 1694

	if (rc == 0)
1695
		cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1696 1697
	else
		kref_put(&rdata->refcount, cifs_readdata_release);
J
Jeff Layton 已提交
1698 1699 1700 1701 1702

	cifs_small_buf_release(smb);
	return rc;
}

L
Linus Torvalds 已提交
1703
int
1704 1705
CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
	    unsigned int *nbytes, char **buf, int *pbuf_type)
L
Linus Torvalds 已提交
1706 1707 1708 1709 1710
{
	int rc = -EACCES;
	READ_REQ *pSMB = NULL;
	READ_RSP *pSMBr = NULL;
	char *pReadData = NULL;
1711
	int wct;
1712 1713
	int resp_buf_type = 0;
	struct kvec iov[1];
1714
	struct kvec rsp_iov;
1715 1716 1717
	__u32 pid = io_parms->pid;
	__u16 netfid = io_parms->netfid;
	__u64 offset = io_parms->offset;
1718
	struct cifs_tcon *tcon = io_parms->tcon;
1719
	unsigned int count = io_parms->length;
L
Linus Torvalds 已提交
1720

1721
	cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
S
Steve French 已提交
1722
	if (tcon->ses->capabilities & CAP_LARGE_FILES)
1723
		wct = 12;
1724
	else {
1725
		wct = 10; /* old style read */
1726
		if ((offset >> 32) > 0)  {
1727 1728 1729 1730
			/* can not handle this big offset for old */
			return -EIO;
		}
	}
L
Linus Torvalds 已提交
1731 1732

	*nbytes = 0;
1733
	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
L
Linus Torvalds 已提交
1734 1735 1736
	if (rc)
		return rc;

1737 1738 1739
	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));

L
Linus Torvalds 已提交
1740 1741 1742 1743
	/* tcon and ses pointer are checked in smb_init */
	if (tcon->ses->server == NULL)
		return -ECONNABORTED;

1744
	pSMB->AndXCommand = 0xFF;       /* none */
L
Linus Torvalds 已提交
1745
	pSMB->Fid = netfid;
1746
	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
S
Steve French 已提交
1747
	if (wct == 12)
1748
		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1749

L
Linus Torvalds 已提交
1750 1751 1752
	pSMB->Remaining = 0;
	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
S
Steve French 已提交
1753
	if (wct == 12)
1754 1755 1756
		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
	else {
		/* old style read */
1757
		struct smb_com_readx_req *pSMBW =
1758
			(struct smb_com_readx_req *)pSMB;
1759
		pSMBW->ByteCount = 0;
1760
	}
1761 1762

	iov[0].iov_base = (char *)pSMB;
1763
	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
1764 1765 1766
	rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
			  CIFS_LOG_ERROR, &rsp_iov);
	cifs_small_buf_release(pSMB);
1767
	cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
1768
	pSMBr = (READ_RSP *)rsp_iov.iov_base;
L
Linus Torvalds 已提交
1769
	if (rc) {
1770
		cifs_dbg(VFS, "Send error in read = %d\n", rc);
L
Linus Torvalds 已提交
1771 1772 1773 1774 1775 1776 1777
	} else {
		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
		data_length = data_length << 16;
		data_length += le16_to_cpu(pSMBr->DataLength);
		*nbytes = data_length;

		/*check that DataLength would not go beyond end of SMB */
1778
		if ((data_length > CIFSMaxBufSize)
L
Linus Torvalds 已提交
1779
				|| (data_length > count)) {
1780
			cifs_dbg(FYI, "bad length %d for count %d\n",
1781
				 data_length, count);
L
Linus Torvalds 已提交
1782 1783 1784
			rc = -EIO;
			*nbytes = 0;
		} else {
1785
			pReadData = (char *) (&pSMBr->hdr.Protocol) +
1786 1787
					le16_to_cpu(pSMBr->DataOffset);
/*			if (rc = copy_to_user(buf, pReadData, data_length)) {
1788
				cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
1789
				rc = -EFAULT;
1790
			}*/ /* can not use copy_to_user when using page cache*/
S
Steve French 已提交
1791
			if (*buf)
1792
				memcpy(*buf, pReadData, data_length);
L
Linus Torvalds 已提交
1793 1794 1795
		}
	}

S
Steve French 已提交
1796
	if (*buf) {
1797
		free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
S
Steve French 已提交
1798
	} else if (resp_buf_type != CIFS_NO_BUFFER) {
1799
		/* return buffer to caller to free */
1800
		*buf = rsp_iov.iov_base;
S
Steve French 已提交
1801
		if (resp_buf_type == CIFS_SMALL_BUFFER)
1802
			*pbuf_type = CIFS_SMALL_BUFFER;
S
Steve French 已提交
1803
		else if (resp_buf_type == CIFS_LARGE_BUFFER)
1804
			*pbuf_type = CIFS_LARGE_BUFFER;
1805
	} /* else no valid buffer on return - leave as null */
1806 1807

	/* Note: On -EAGAIN error only caller can retry on handle based calls
L
Linus Torvalds 已提交
1808 1809 1810 1811
		since file handle passed in no longer valid */
	return rc;
}

1812

L
Linus Torvalds 已提交
1813
int
1814
CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
1815
	     unsigned int *nbytes, const char *buf)
L
Linus Torvalds 已提交
1816 1817 1818 1819
{
	int rc = -EACCES;
	WRITE_REQ *pSMB = NULL;
	WRITE_RSP *pSMBr = NULL;
1820
	int bytes_returned, wct;
L
Linus Torvalds 已提交
1821 1822
	__u32 bytes_sent;
	__u16 byte_count;
1823 1824 1825
	__u32 pid = io_parms->pid;
	__u16 netfid = io_parms->netfid;
	__u64 offset = io_parms->offset;
1826
	struct cifs_tcon *tcon = io_parms->tcon;
1827
	unsigned int count = io_parms->length;
L
Linus Torvalds 已提交
1828

1829 1830
	*nbytes = 0;

1831
	/* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
S
Steve French 已提交
1832
	if (tcon->ses == NULL)
1833 1834
		return -ECONNABORTED;

S
Steve French 已提交
1835
	if (tcon->ses->capabilities & CAP_LARGE_FILES)
1836
		wct = 14;
1837
	else {
1838
		wct = 12;
1839 1840 1841 1842 1843
		if ((offset >> 32) > 0) {
			/* can not handle big offset for old srv */
			return -EIO;
		}
	}
1844 1845

	rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
L
Linus Torvalds 已提交
1846 1847 1848
		      (void **) &pSMBr);
	if (rc)
		return rc;
1849 1850 1851 1852

	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));

L
Linus Torvalds 已提交
1853 1854 1855 1856 1857 1858 1859
	/* tcon and ses pointer are checked in smb_init */
	if (tcon->ses->server == NULL)
		return -ECONNABORTED;

	pSMB->AndXCommand = 0xFF;	/* none */
	pSMB->Fid = netfid;
	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
S
Steve French 已提交
1860
	if (wct == 14)
1861
		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1862

L
Linus Torvalds 已提交
1863 1864 1865 1866
	pSMB->Reserved = 0xFFFFFFFF;
	pSMB->WriteMode = 0;
	pSMB->Remaining = 0;

1867
	/* Can increase buffer size if buffer is big enough in some cases ie we
L
Linus Torvalds 已提交
1868 1869 1870
	can send more if LARGE_WRITE_X capability returned by the server and if
	our buffer is big enough or if we convert to iovecs on socket writes
	and eliminate the copy to the CIFS buffer */
S
Steve French 已提交
1871
	if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
L
Linus Torvalds 已提交
1872 1873 1874 1875 1876 1877 1878 1879 1880
		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
	} else {
		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
			 & ~0xFF;
	}

	if (bytes_sent > count)
		bytes_sent = count;
	pSMB->DataOffset =
1881
		cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
S
Steve French 已提交
1882
	if (buf)
1883
		memcpy(pSMB->Data, buf, bytes_sent);
1884
	else if (count != 0) {
L
Linus Torvalds 已提交
1885 1886 1887
		/* No buffer */
		cifs_buf_release(pSMB);
		return -EINVAL;
1888
	} /* else setting file size with write of zero bytes */
S
Steve French 已提交
1889
	if (wct == 14)
1890
		byte_count = bytes_sent + 1; /* pad */
S
Steve French 已提交
1891
	else /* wct == 12 */
1892
		byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
S
Steve French 已提交
1893

L
Linus Torvalds 已提交
1894 1895
	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1896
	inc_rfc1001_len(pSMB, byte_count);
1897

S
Steve French 已提交
1898
	if (wct == 14)
1899
		pSMB->ByteCount = cpu_to_le16(byte_count);
1900 1901 1902
	else { /* old style write has byte count 4 bytes earlier
		  so 4 bytes pad  */
		struct smb_com_writex_req *pSMBW =
1903 1904 1905
			(struct smb_com_writex_req *)pSMB;
		pSMBW->ByteCount = cpu_to_le16(byte_count);
	}
L
Linus Torvalds 已提交
1906 1907

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1908
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1909
	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
L
Linus Torvalds 已提交
1910
	if (rc) {
1911
		cifs_dbg(FYI, "Send error in write = %d\n", rc);
L
Linus Torvalds 已提交
1912 1913 1914 1915
	} else {
		*nbytes = le16_to_cpu(pSMBr->CountHigh);
		*nbytes = (*nbytes) << 16;
		*nbytes += le16_to_cpu(pSMBr->Count);
1916 1917 1918 1919 1920 1921 1922 1923

		/*
		 * Mask off high 16 bits when bytes written as returned by the
		 * server is greater than bytes requested by the client. Some
		 * OS/2 servers are known to set incorrect CountHigh values.
		 */
		if (*nbytes > count)
			*nbytes &= 0xFFFF;
L
Linus Torvalds 已提交
1924 1925 1926 1927
	}

	cifs_buf_release(pSMB);

1928
	/* Note: On -EAGAIN error only caller can retry on handle based calls
L
Linus Torvalds 已提交
1929 1930 1931 1932 1933
		since file handle passed in no longer valid */

	return rc;
}

J
Jeff Layton 已提交
1934 1935 1936 1937 1938
void
cifs_writedata_release(struct kref *refcount)
{
	struct cifs_writedata *wdata = container_of(refcount,
					struct cifs_writedata, refcount);
1939 1940 1941 1942 1943 1944
#ifdef CONFIG_CIFS_SMB_DIRECT
	if (wdata->mr) {
		smbd_deregister_mr(wdata->mr);
		wdata->mr = NULL;
	}
#endif
J
Jeff Layton 已提交
1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958

	if (wdata->cfile)
		cifsFileInfo_put(wdata->cfile);

	kfree(wdata);
}

/*
 * Write failed with a retryable error. Resend the write request. It's also
 * possible that the page was redirtied so re-clean the page.
 */
static void
cifs_writev_requeue(struct cifs_writedata *wdata)
{
1959
	int i, rc = 0;
1960
	struct inode *inode = d_inode(wdata->cfile->dentry);
1961
	struct TCP_Server_Info *server;
1962
	unsigned int rest_len;
J
Jeff Layton 已提交
1963

1964 1965 1966
	server = tlink_tcon(wdata->cfile->tlink)->ses->server;
	i = 0;
	rest_len = wdata->bytes;
J
Jeff Layton 已提交
1967
	do {
1968 1969 1970 1971 1972
		struct cifs_writedata *wdata2;
		unsigned int j, nr_pages, wsize, tailsz, cur_len;

		wsize = server->ops->wp_retry_size(inode);
		if (wsize < rest_len) {
1973
			nr_pages = wsize / PAGE_SIZE;
1974 1975 1976 1977
			if (!nr_pages) {
				rc = -ENOTSUPP;
				break;
			}
1978 1979
			cur_len = nr_pages * PAGE_SIZE;
			tailsz = PAGE_SIZE;
1980
		} else {
1981
			nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
1982
			cur_len = rest_len;
1983
			tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
1984
		}
J
Jeff Layton 已提交
1985

1986 1987 1988 1989
		wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
		if (!wdata2) {
			rc = -ENOMEM;
			break;
1990
		}
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000

		for (j = 0; j < nr_pages; j++) {
			wdata2->pages[j] = wdata->pages[i + j];
			lock_page(wdata2->pages[j]);
			clear_page_dirty_for_io(wdata2->pages[j]);
		}

		wdata2->sync_mode = wdata->sync_mode;
		wdata2->nr_pages = nr_pages;
		wdata2->offset = page_offset(wdata2->pages[0]);
2001
		wdata2->pagesz = PAGE_SIZE;
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
		wdata2->tailsz = tailsz;
		wdata2->bytes = cur_len;

		wdata2->cfile = find_writable_file(CIFS_I(inode), false);
		if (!wdata2->cfile) {
			cifs_dbg(VFS, "No writable handles for inode\n");
			rc = -EBADF;
			break;
		}
		wdata2->pid = wdata2->cfile->pid;
		rc = server->ops->async_writev(wdata2, cifs_writedata_release);

		for (j = 0; j < nr_pages; j++) {
			unlock_page(wdata2->pages[j]);
			if (rc != 0 && rc != -EAGAIN) {
				SetPageError(wdata2->pages[j]);
				end_page_writeback(wdata2->pages[j]);
2019
				put_page(wdata2->pages[j]);
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
			}
		}

		if (rc) {
			kref_put(&wdata2->refcount, cifs_writedata_release);
			if (rc == -EAGAIN)
				continue;
			break;
		}

		rest_len -= cur_len;
		i += nr_pages;
	} while (i < wdata->nr_pages);
J
Jeff Layton 已提交
2033 2034 2035 2036 2037

	mapping_set_error(inode->i_mapping, rc);
	kref_put(&wdata->refcount, cifs_writedata_release);
}

2038
void
J
Jeff Layton 已提交
2039 2040 2041 2042
cifs_writev_complete(struct work_struct *work)
{
	struct cifs_writedata *wdata = container_of(work,
						struct cifs_writedata, work);
2043
	struct inode *inode = d_inode(wdata->cfile->dentry);
J
Jeff Layton 已提交
2044 2045 2046
	int i = 0;

	if (wdata->result == 0) {
2047
		spin_lock(&inode->i_lock);
J
Jeff Layton 已提交
2048
		cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
2049
		spin_unlock(&inode->i_lock);
J
Jeff Layton 已提交
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
		cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
					 wdata->bytes);
	} else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
		return cifs_writev_requeue(wdata);

	for (i = 0; i < wdata->nr_pages; i++) {
		struct page *page = wdata->pages[i];
		if (wdata->result == -EAGAIN)
			__set_page_dirty_nobuffers(page);
		else if (wdata->result < 0)
			SetPageError(page);
		end_page_writeback(page);
2062
		put_page(page);
J
Jeff Layton 已提交
2063 2064 2065 2066 2067 2068 2069
	}
	if (wdata->result != -EAGAIN)
		mapping_set_error(inode->i_mapping, wdata->result);
	kref_put(&wdata->refcount, cifs_writedata_release);
}

struct cifs_writedata *
2070
cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
J
Jeff Layton 已提交
2071 2072 2073 2074 2075
{
	struct cifs_writedata *wdata;

	/* writedata + number of page pointers */
	wdata = kzalloc(sizeof(*wdata) +
2076
			sizeof(struct page *) * nr_pages, GFP_NOFS);
J
Jeff Layton 已提交
2077 2078
	if (wdata != NULL) {
		kref_init(&wdata->refcount);
2079 2080 2081
		INIT_LIST_HEAD(&wdata->list);
		init_completion(&wdata->done);
		INIT_WORK(&wdata->work, complete);
J
Jeff Layton 已提交
2082 2083 2084 2085 2086
	}
	return wdata;
}

/*
2087
 * Check the mid_state and signature on received buffer (if any), and queue the
J
Jeff Layton 已提交
2088 2089 2090 2091 2092 2093
 * workqueue completion task.
 */
static void
cifs_writev_callback(struct mid_q_entry *mid)
{
	struct cifs_writedata *wdata = mid->callback_data;
2094
	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
J
Jeff Layton 已提交
2095 2096 2097
	unsigned int written;
	WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;

2098
	switch (mid->mid_state) {
J
Jeff Layton 已提交
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129
	case MID_RESPONSE_RECEIVED:
		wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
		if (wdata->result != 0)
			break;

		written = le16_to_cpu(smb->CountHigh);
		written <<= 16;
		written += le16_to_cpu(smb->Count);
		/*
		 * Mask off high 16 bits when bytes written as returned
		 * by the server is greater than bytes requested by the
		 * client. OS/2 servers are known to set incorrect
		 * CountHigh values.
		 */
		if (written > wdata->bytes)
			written &= 0xFFFF;

		if (written < wdata->bytes)
			wdata->result = -ENOSPC;
		else
			wdata->bytes = written;
		break;
	case MID_REQUEST_SUBMITTED:
	case MID_RETRY_NEEDED:
		wdata->result = -EAGAIN;
		break;
	default:
		wdata->result = -EIO;
		break;
	}

J
Jeff Layton 已提交
2130
	queue_work(cifsiod_wq, &wdata->work);
J
Jeff Layton 已提交
2131
	DeleteMidQEntry(mid);
2132
	add_credits(tcon->ses->server, 1, 0);
J
Jeff Layton 已提交
2133 2134 2135 2136
}

/* cifs_async_writev - send an async write, and set up mid to handle result */
int
2137 2138
cifs_async_writev(struct cifs_writedata *wdata,
		  void (*release)(struct kref *kref))
J
Jeff Layton 已提交
2139
{
2140
	int rc = -EACCES;
J
Jeff Layton 已提交
2141 2142
	WRITE_REQ *smb = NULL;
	int wct;
2143
	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
2144
	struct kvec iov[2];
2145
	struct smb_rqst rqst = { };
J
Jeff Layton 已提交
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160

	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
		wct = 14;
	} else {
		wct = 12;
		if (wdata->offset >> 32 > 0) {
			/* can not handle big offset for old srv */
			return -EIO;
		}
	}

	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
	if (rc)
		goto async_writev_out;

2161 2162
	smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
2163

J
Jeff Layton 已提交
2164
	smb->AndXCommand = 0xFF;	/* none */
2165
	smb->Fid = wdata->cfile->fid.netfid;
J
Jeff Layton 已提交
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
	smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
	if (wct == 14)
		smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
	smb->Reserved = 0xFFFFFFFF;
	smb->WriteMode = 0;
	smb->Remaining = 0;

	smb->DataOffset =
	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);

	/* 4 for RFC1001 length + 1 for BCC */
2177 2178 2179 2180
	iov[0].iov_len = 4;
	iov[0].iov_base = smb;
	iov[1].iov_len = get_rfc1002_length(smb) + 1;
	iov[1].iov_base = (char *)smb + 4;
J
Jeff Layton 已提交
2181

2182 2183
	rqst.rq_iov = iov;
	rqst.rq_nvec = 2;
2184 2185 2186 2187
	rqst.rq_pages = wdata->pages;
	rqst.rq_npages = wdata->nr_pages;
	rqst.rq_pagesz = wdata->pagesz;
	rqst.rq_tailsz = wdata->tailsz;
J
Jeff Layton 已提交
2188

2189 2190
	cifs_dbg(FYI, "async write at %llu %u bytes\n",
		 wdata->offset, wdata->bytes);
J
Jeff Layton 已提交
2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203

	smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
	smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);

	if (wct == 14) {
		inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
		put_bcc(wdata->bytes + 1, &smb->hdr);
	} else {
		/* wct == 12 */
		struct smb_com_writex_req *smbw =
				(struct smb_com_writex_req *)smb;
		inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
		put_bcc(wdata->bytes + 5, &smbw->hdr);
2204
		iov[1].iov_len += 4; /* pad bigger by four bytes */
J
Jeff Layton 已提交
2205 2206 2207
	}

	kref_get(&wdata->refcount);
2208
	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
P
Pavel Shilovsky 已提交
2209
				cifs_writev_callback, NULL, wdata, 0);
J
Jeff Layton 已提交
2210 2211

	if (rc == 0)
2212
		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
J
Jeff Layton 已提交
2213
	else
2214
		kref_put(&wdata->refcount, release);
J
Jeff Layton 已提交
2215 2216 2217 2218 2219 2220

async_writev_out:
	cifs_small_buf_release(smb);
	return rc;
}

2221
int
2222
CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
2223
	      unsigned int *nbytes, struct kvec *iov, int n_vec)
L
Linus Torvalds 已提交
2224 2225 2226
{
	int rc = -EACCES;
	WRITE_REQ *pSMB = NULL;
2227
	int wct;
2228
	int smb_hdr_len;
2229
	int resp_buf_type = 0;
2230 2231 2232
	__u32 pid = io_parms->pid;
	__u16 netfid = io_parms->netfid;
	__u64 offset = io_parms->offset;
2233
	struct cifs_tcon *tcon = io_parms->tcon;
2234
	unsigned int count = io_parms->length;
2235
	struct kvec rsp_iov;
L
Linus Torvalds 已提交
2236

2237 2238
	*nbytes = 0;

2239
	cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
2240

2241
	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2242
		wct = 14;
2243
	} else {
2244
		wct = 12;
2245 2246 2247 2248 2249
		if ((offset >> 32) > 0) {
			/* can not handle big offset for old srv */
			return -EIO;
		}
	}
2250
	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
L
Linus Torvalds 已提交
2251 2252
	if (rc)
		return rc;
2253 2254 2255 2256

	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));

L
Linus Torvalds 已提交
2257 2258 2259 2260
	/* tcon and ses pointer are checked in smb_init */
	if (tcon->ses->server == NULL)
		return -ECONNABORTED;

2261
	pSMB->AndXCommand = 0xFF;	/* none */
L
Linus Torvalds 已提交
2262 2263
	pSMB->Fid = netfid;
	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
S
Steve French 已提交
2264
	if (wct == 14)
2265
		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
L
Linus Torvalds 已提交
2266 2267 2268
	pSMB->Reserved = 0xFFFFFFFF;
	pSMB->WriteMode = 0;
	pSMB->Remaining = 0;
2269

L
Linus Torvalds 已提交
2270
	pSMB->DataOffset =
2271
	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
L
Linus Torvalds 已提交
2272

2273 2274
	pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
	pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
2275 2276
	/* header + 1 byte pad */
	smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
S
Steve French 已提交
2277
	if (wct == 14)
2278
		inc_rfc1001_len(pSMB, count + 1);
2279
	else /* wct == 12 */
2280
		inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
S
Steve French 已提交
2281
	if (wct == 14)
2282 2283
		pSMB->ByteCount = cpu_to_le16(count + 1);
	else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
2284
		struct smb_com_writex_req *pSMBW =
2285 2286 2287
				(struct smb_com_writex_req *)pSMB;
		pSMBW->ByteCount = cpu_to_le16(count + 5);
	}
2288
	iov[0].iov_base = pSMB;
S
Steve French 已提交
2289
	if (wct == 14)
2290 2291 2292
		iov[0].iov_len = smb_hdr_len + 4;
	else /* wct == 12 pad bigger by four bytes */
		iov[0].iov_len = smb_hdr_len + 8;
2293

2294 2295 2296
	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
			  &rsp_iov);
	cifs_small_buf_release(pSMB);
2297
	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
L
Linus Torvalds 已提交
2298
	if (rc) {
2299
		cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
S
Steve French 已提交
2300
	} else if (resp_buf_type == 0) {
2301 2302
		/* presumably this can not happen, but best to be safe */
		rc = -EIO;
2303
	} else {
2304
		WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
2305 2306 2307
		*nbytes = le16_to_cpu(pSMBr->CountHigh);
		*nbytes = (*nbytes) << 16;
		*nbytes += le16_to_cpu(pSMBr->Count);
2308 2309 2310 2311 2312 2313 2314 2315

		/*
		 * Mask off high 16 bits when bytes written as returned by the
		 * server is greater than bytes requested by the client. OS/2
		 * servers are known to set incorrect CountHigh values.
		 */
		if (*nbytes > count)
			*nbytes &= 0xFFFF;
2316
	}
L
Linus Torvalds 已提交
2317

2318
	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
L
Linus Torvalds 已提交
2319

2320
	/* Note: On -EAGAIN error only caller can retry on handle based calls
L
Linus Torvalds 已提交
2321 2322 2323 2324
		since file handle passed in no longer valid */

	return rc;
}
2325

2326 2327
int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
	       const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
2328 2329 2330 2331 2332
	       const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
{
	int rc = 0;
	LOCK_REQ *pSMB = NULL;
	struct kvec iov[2];
2333
	struct kvec rsp_iov;
2334 2335 2336
	int resp_buf_type;
	__u16 count;

2337 2338
	cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
		 num_lock, num_unlock);
2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360

	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
	if (rc)
		return rc;

	pSMB->Timeout = 0;
	pSMB->NumberOfLocks = cpu_to_le16(num_lock);
	pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
	pSMB->LockType = lock_type;
	pSMB->AndXCommand = 0xFF; /* none */
	pSMB->Fid = netfid; /* netfid stays le */

	count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
	inc_rfc1001_len(pSMB, count);
	pSMB->ByteCount = cpu_to_le16(count);

	iov[0].iov_base = (char *)pSMB;
	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
			 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
	iov[1].iov_base = (char *)buf;
	iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);

2361
	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
2362 2363 2364
	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
			  &rsp_iov);
	cifs_small_buf_release(pSMB);
2365
	if (rc)
2366
		cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
2367 2368 2369

	return rc;
}
2370

L
Linus Torvalds 已提交
2371
int
2372
CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
2373
	    const __u16 smb_file_id, const __u32 netpid, const __u64 len,
L
Linus Torvalds 已提交
2374
	    const __u64 offset, const __u32 numUnlock,
2375 2376
	    const __u32 numLock, const __u8 lockType,
	    const bool waitFlag, const __u8 oplock_level)
L
Linus Torvalds 已提交
2377 2378 2379
{
	int rc = 0;
	LOCK_REQ *pSMB = NULL;
S
Steve French 已提交
2380
/*	LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
L
Linus Torvalds 已提交
2381
	int bytes_returned;
2382
	int flags = 0;
L
Linus Torvalds 已提交
2383 2384
	__u16 count;

2385 2386
	cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
		 (int)waitFlag, numLock);
2387 2388
	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);

L
Linus Torvalds 已提交
2389 2390 2391
	if (rc)
		return rc;

S
Steve French 已提交
2392
	if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
2393 2394
		/* no response expected */
		flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
L
Linus Torvalds 已提交
2395
		pSMB->Timeout = 0;
2396
	} else if (waitFlag) {
2397
		flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
L
Linus Torvalds 已提交
2398 2399 2400 2401 2402 2403 2404 2405
		pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
	} else {
		pSMB->Timeout = 0;
	}

	pSMB->NumberOfLocks = cpu_to_le16(numLock);
	pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
	pSMB->LockType = lockType;
2406
	pSMB->OplockLevel = oplock_level;
L
Linus Torvalds 已提交
2407 2408 2409
	pSMB->AndXCommand = 0xFF;	/* none */
	pSMB->Fid = smb_file_id; /* netfid stays le */

S
Steve French 已提交
2410
	if ((numLock != 0) || (numUnlock != 0)) {
2411
		pSMB->Locks[0].Pid = cpu_to_le16(netpid);
L
Linus Torvalds 已提交
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
		/* BB where to store pid high? */
		pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
		pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
		pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
		pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
		count = sizeof(LOCKING_ANDX_RANGE);
	} else {
		/* oplock break */
		count = 0;
	}
2422
	inc_rfc1001_len(pSMB, count);
L
Linus Torvalds 已提交
2423 2424
	pSMB->ByteCount = cpu_to_le16(count);

2425
	if (waitFlag)
J
[CIFS]  
Jeremy Allison 已提交
2426
		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
S
Steve French 已提交
2427
			(struct smb_hdr *) pSMB, &bytes_returned);
2428
	else
2429
		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
2430
	cifs_small_buf_release(pSMB);
2431
	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
S
Steve French 已提交
2432
	if (rc)
2433
		cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
L
Linus Torvalds 已提交
2434

2435
	/* Note: On -EAGAIN error only caller can retry on handle based calls
L
Linus Torvalds 已提交
2436 2437 2438 2439
	since file handle passed in no longer valid */
	return rc;
}

2440
int
2441
CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
2442 2443 2444 2445
		const __u16 smb_file_id, const __u32 netpid,
		const loff_t start_offset, const __u64 len,
		struct file_lock *pLockData, const __u16 lock_type,
		const bool waitFlag)
2446 2447 2448 2449 2450
{
	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
	struct cifs_posix_lock *parm_data;
	int rc = 0;
2451
	int timeout = 0;
2452
	int bytes_returned = 0;
2453
	int resp_buf_type = 0;
2454
	__u16 params, param_offset, offset, byte_count, count;
2455
	struct kvec iov[1];
2456
	struct kvec rsp_iov;
2457

2458
	cifs_dbg(FYI, "Posix Lock\n");
2459

2460 2461 2462 2463 2464 2465 2466
	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);

	if (rc)
		return rc;

	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;

2467
	params = 6;
2468 2469 2470 2471 2472 2473 2474 2475 2476
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
	offset = param_offset + params;

	count = sizeof(struct cifs_posix_lock);
	pSMB->MaxParameterCount = cpu_to_le16(2);
S
Steve French 已提交
2477
	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
2478 2479
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
2480
	if (pLockData)
2481 2482 2483 2484 2485 2486 2487 2488 2489
		pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
	else
		pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
	byte_count = 3 /* pad */  + params + count;
	pSMB->DataCount = cpu_to_le16(count);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
2490
	parm_data = (struct cifs_posix_lock *)
2491 2492 2493
			(((char *) &pSMB->hdr.Protocol) + offset);

	parm_data->lock_type = cpu_to_le16(lock_type);
S
Steve French 已提交
2494
	if (waitFlag) {
2495
		timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
2496
		parm_data->lock_flags = cpu_to_le16(1);
2497 2498 2499 2500
		pSMB->Timeout = cpu_to_le32(-1);
	} else
		pSMB->Timeout = 0;

2501
	parm_data->pid = cpu_to_le32(netpid);
2502
	parm_data->start = cpu_to_le64(start_offset);
2503
	parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
2504 2505

	pSMB->DataOffset = cpu_to_le16(offset);
2506
	pSMB->Fid = smb_file_id;
2507 2508
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
	pSMB->Reserved4 = 0;
2509
	inc_rfc1001_len(pSMB, byte_count);
2510
	pSMB->ByteCount = cpu_to_le16(byte_count);
J
[CIFS]  
Jeremy Allison 已提交
2511 2512 2513 2514
	if (waitFlag) {
		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
			(struct smb_hdr *) pSMBr, &bytes_returned);
	} else {
2515
		iov[0].iov_base = (char *)pSMB;
2516
		iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
2517
		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2518 2519
				&resp_buf_type, timeout, &rsp_iov);
		pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
J
[CIFS]  
Jeremy Allison 已提交
2520
	}
2521
	cifs_small_buf_release(pSMB);
J
[CIFS]  
Jeremy Allison 已提交
2522

2523
	if (rc) {
2524
		cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
2525
	} else if (pLockData) {
2526 2527 2528 2529 2530
		/* lock structure can be returned on get */
		__u16 data_offset;
		__u16 data_count;
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

2531
		if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
2532 2533 2534 2535 2536
			rc = -EIO;      /* bad smb */
			goto plk_err_exit;
		}
		data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
		data_count  = le16_to_cpu(pSMBr->t2.DataCount);
S
Steve French 已提交
2537
		if (data_count < sizeof(struct cifs_posix_lock)) {
2538 2539 2540 2541 2542
			rc = -EIO;
			goto plk_err_exit;
		}
		parm_data = (struct cifs_posix_lock *)
			((char *)&pSMBr->hdr.Protocol + data_offset);
2543
		if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
2544
			pLockData->fl_type = F_UNLCK;
2545 2546
		else {
			if (parm_data->lock_type ==
2547
					cpu_to_le16(CIFS_RDLCK))
2548 2549
				pLockData->fl_type = F_RDLCK;
			else if (parm_data->lock_type ==
2550
					cpu_to_le16(CIFS_WRLCK))
2551 2552
				pLockData->fl_type = F_WRLCK;

S
Steve French 已提交
2553 2554 2555
			pLockData->fl_start = le64_to_cpu(parm_data->start);
			pLockData->fl_end = pLockData->fl_start +
					le64_to_cpu(parm_data->length) - 1;
2556
			pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
2557
		}
2558
	}
2559

2560
plk_err_exit:
2561
	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
2562

2563 2564 2565 2566 2567 2568 2569
	/* Note: On -EAGAIN error only caller can retry on handle based calls
	   since file handle passed in no longer valid */

	return rc;
}


L
Linus Torvalds 已提交
2570
int
2571
CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
L
Linus Torvalds 已提交
2572 2573 2574
{
	int rc = 0;
	CLOSE_REQ *pSMB = NULL;
2575
	cifs_dbg(FYI, "In CIFSSMBClose\n");
L
Linus Torvalds 已提交
2576 2577 2578

/* do not retry on dead session on close */
	rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
S
Steve French 已提交
2579
	if (rc == -EAGAIN)
L
Linus Torvalds 已提交
2580 2581 2582 2583 2584
		return 0;
	if (rc)
		return rc;

	pSMB->FileID = (__u16) smb_file_id;
2585
	pSMB->LastWriteTime = 0xFFFFFFFF;
L
Linus Torvalds 已提交
2586
	pSMB->ByteCount = 0;
2587
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2588
	cifs_small_buf_release(pSMB);
2589
	cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
L
Linus Torvalds 已提交
2590
	if (rc) {
S
Steve French 已提交
2591
		if (rc != -EINTR) {
L
Linus Torvalds 已提交
2592
			/* EINTR is expected when user ctl-c to kill app */
2593
			cifs_dbg(VFS, "Send error in Close = %d\n", rc);
L
Linus Torvalds 已提交
2594 2595 2596 2597
		}
	}

	/* Since session is dead, file will be closed on server already */
S
Steve French 已提交
2598
	if (rc == -EAGAIN)
L
Linus Torvalds 已提交
2599 2600 2601 2602 2603
		rc = 0;

	return rc;
}

2604
int
2605
CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
2606 2607 2608
{
	int rc = 0;
	FLUSH_REQ *pSMB = NULL;
2609
	cifs_dbg(FYI, "In CIFSSMBFlush\n");
2610 2611 2612 2613 2614 2615 2616

	rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
	if (rc)
		return rc;

	pSMB->FileID = (__u16) smb_file_id;
	pSMB->ByteCount = 0;
2617
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
2618
	cifs_small_buf_release(pSMB);
2619
	cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
2620
	if (rc)
2621
		cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
2622 2623 2624 2625

	return rc;
}

L
Linus Torvalds 已提交
2626
int
2627
CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2628 2629
	      const char *from_name, const char *to_name,
	      struct cifs_sb_info *cifs_sb)
L
Linus Torvalds 已提交
2630 2631 2632 2633 2634 2635 2636
{
	int rc = 0;
	RENAME_REQ *pSMB = NULL;
	RENAME_RSP *pSMBr = NULL;
	int bytes_returned;
	int name_len, name_len2;
	__u16 count;
2637
	int remap = cifs_remap(cifs_sb);
L
Linus Torvalds 已提交
2638

2639
	cifs_dbg(FYI, "In CIFSSMBRename\n");
L
Linus Torvalds 已提交
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651
renameRetry:
	rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	pSMB->BufferFormat = 0x04;
	pSMB->SearchAttributes =
	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
			ATTR_DIRECTORY);

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2652 2653 2654
		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
					      from_name, PATH_MAX,
					      cifs_sb->local_nls, remap);
L
Linus Torvalds 已提交
2655 2656 2657 2658 2659 2660
		name_len++;	/* trailing null */
		name_len *= 2;
		pSMB->OldFileName[name_len] = 0x04;	/* pad */
	/* protocol requires ASCII signature byte on Unicode string */
		pSMB->OldFileName[name_len + 1] = 0x00;
		name_len2 =
2661
		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2662 2663
				       to_name, PATH_MAX, cifs_sb->local_nls,
				       remap);
L
Linus Torvalds 已提交
2664 2665
		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
		name_len2 *= 2;	/* convert to bytes */
2666
	} else {	/* BB improve the check for buffer overruns BB */
2667
		name_len = strnlen(from_name, PATH_MAX);
L
Linus Torvalds 已提交
2668
		name_len++;	/* trailing null */
2669 2670
		strncpy(pSMB->OldFileName, from_name, name_len);
		name_len2 = strnlen(to_name, PATH_MAX);
L
Linus Torvalds 已提交
2671 2672
		name_len2++;	/* trailing null */
		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
2673
		strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
L
Linus Torvalds 已提交
2674 2675 2676 2677 2678
		name_len2++;	/* trailing null */
		name_len2++;	/* signature byte */
	}

	count = 1 /* 1st signature byte */  + name_len + name_len2;
2679
	inc_rfc1001_len(pSMB, count);
L
Linus Torvalds 已提交
2680 2681 2682 2683
	pSMB->ByteCount = cpu_to_le16(count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2684
	cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
S
Steve French 已提交
2685
	if (rc)
2686
		cifs_dbg(FYI, "Send error in rename = %d\n", rc);
L
Linus Torvalds 已提交
2687 2688 2689 2690 2691 2692 2693 2694 2695

	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto renameRetry;

	return rc;
}

2696
int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
2697
		int netfid, const char *target_name,
2698
		const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
2699 2700 2701
{
	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
2702
	struct set_file_rename *rename_info;
L
Linus Torvalds 已提交
2703 2704 2705 2706 2707 2708 2709
	char *data_offset;
	char dummy_string[30];
	int rc = 0;
	int bytes_returned = 0;
	int len_of_str;
	__u16 params, param_offset, offset, count, byte_count;

2710
	cifs_dbg(FYI, "Rename to File by handle\n");
L
Linus Torvalds 已提交
2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727
	rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
			(void **) &pSMBr);
	if (rc)
		return rc;

	params = 6;
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
	offset = param_offset + params;

	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
	rename_info = (struct set_file_rename *) data_offset;
	pSMB->MaxParameterCount = cpu_to_le16(2);
S
Steve French 已提交
2728
	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
L
Linus Torvalds 已提交
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
	byte_count = 3 /* pad */  + params;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	/* construct random name ".cifs_tmp<inodenum><mid>" */
	rename_info->overwrite = cpu_to_le32(1);
	rename_info->root_fid  = 0;
	/* unicode only call */
S
Steve French 已提交
2741
	if (target_name == NULL) {
2742
		sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2743 2744
		len_of_str =
			cifsConvertToUTF16((__le16 *)rename_info->target_name,
2745
					dummy_string, 24, nls_codepage, remap);
L
Linus Torvalds 已提交
2746
	} else {
2747 2748
		len_of_str =
			cifsConvertToUTF16((__le16 *)rename_info->target_name,
2749 2750
					target_name, PATH_MAX, nls_codepage,
					remap);
L
Linus Torvalds 已提交
2751 2752
	}
	rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2753
	count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
L
Linus Torvalds 已提交
2754 2755 2756 2757 2758 2759 2760
	byte_count += count;
	pSMB->DataCount = cpu_to_le16(count);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->Fid = netfid;
	pSMB->InformationLevel =
		cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
	pSMB->Reserved4 = 0;
2761
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
2762 2763
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
2764
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2765
	cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
S
Steve French 已提交
2766
	if (rc)
2767 2768
		cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
			 rc);
2769

L
Linus Torvalds 已提交
2770 2771 2772 2773 2774 2775 2776 2777 2778
	cifs_buf_release(pSMB);

	/* Note: On -EAGAIN error only caller can retry on handle based calls
		since file handle passed in no longer valid */

	return rc;
}

int
2779 2780 2781
CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
	    const char *fromName, const __u16 target_tid, const char *toName,
	    const int flags, const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
2782 2783 2784 2785 2786 2787 2788 2789
{
	int rc = 0;
	COPY_REQ *pSMB = NULL;
	COPY_RSP *pSMBr = NULL;
	int bytes_returned;
	int name_len, name_len2;
	__u16 count;

2790
	cifs_dbg(FYI, "In CIFSSMBCopy\n");
L
Linus Torvalds 已提交
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802
copyRetry:
	rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
			(void **) &pSMBr);
	if (rc)
		return rc;

	pSMB->BufferFormat = 0x04;
	pSMB->Tid2 = target_tid;

	pSMB->Flags = cpu_to_le16(flags & COPY_TREE);

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2803 2804 2805
		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
					      fromName, PATH_MAX, nls_codepage,
					      remap);
L
Linus Torvalds 已提交
2806 2807 2808 2809 2810
		name_len++;     /* trailing null */
		name_len *= 2;
		pSMB->OldFileName[name_len] = 0x04;     /* pad */
		/* protocol requires ASCII signature byte on Unicode string */
		pSMB->OldFileName[name_len + 1] = 0x00;
2811
		name_len2 =
2812 2813
		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
				       toName, PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
2814 2815
		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
		name_len2 *= 2; /* convert to bytes */
2816
	} else { 	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828
		name_len = strnlen(fromName, PATH_MAX);
		name_len++;     /* trailing null */
		strncpy(pSMB->OldFileName, fromName, name_len);
		name_len2 = strnlen(toName, PATH_MAX);
		name_len2++;    /* trailing null */
		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
		name_len2++;    /* trailing null */
		name_len2++;    /* signature byte */
	}

	count = 1 /* 1st signature byte */  + name_len + name_len2;
2829
	inc_rfc1001_len(pSMB, count);
L
Linus Torvalds 已提交
2830 2831 2832 2833 2834
	pSMB->ByteCount = cpu_to_le16(count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
2835 2836
		cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
			 rc, le16_to_cpu(pSMBr->CopyCount));
L
Linus Torvalds 已提交
2837
	}
2838
	cifs_buf_release(pSMB);
L
Linus Torvalds 已提交
2839 2840 2841 2842 2843 2844 2845 2846

	if (rc == -EAGAIN)
		goto copyRetry;

	return rc;
}

int
2847
CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
L
Linus Torvalds 已提交
2848
		      const char *fromName, const char *toName,
2849
		      const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
2850 2851 2852 2853 2854 2855 2856 2857 2858 2859
{
	TRANSACTION2_SPI_REQ *pSMB = NULL;
	TRANSACTION2_SPI_RSP *pSMBr = NULL;
	char *data_offset;
	int name_len;
	int name_len_target;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, param_offset, offset, byte_count;

2860
	cifs_dbg(FYI, "In Symlink Unix style\n");
L
Linus Torvalds 已提交
2861 2862 2863 2864 2865 2866 2867 2868
createSymLinkRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
2869 2870 2871
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
				/* find define for this maxpathcomponent */
					PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
2872 2873 2874
		name_len++;	/* trailing null */
		name_len *= 2;

2875
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886
		name_len = strnlen(fromName, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, fromName, name_len);
	}
	params = 6 + name_len;
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
2887
				InformationLevel) - 4;
L
Linus Torvalds 已提交
2888 2889 2890 2891 2892
	offset = param_offset + params;

	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len_target =
2893 2894 2895
		    cifsConvertToUTF16((__le16 *) data_offset, toName,
				/* find define for this maxpathcomponent */
					PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
2896 2897
		name_len_target++;	/* trailing null */
		name_len_target *= 2;
2898
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918
		name_len_target = strnlen(toName, PATH_MAX);
		name_len_target++;	/* trailing null */
		strncpy(data_offset, toName, name_len_target);
	}

	pSMB->MaxParameterCount = cpu_to_le16(2);
	/* BB find exact max on data count below from sess */
	pSMB->MaxDataCount = cpu_to_le16(1000);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + name_len_target;
	pSMB->DataCount = cpu_to_le16(name_len_target);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
	pSMB->Reserved4 = 0;
2919
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
2920 2921 2922
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2923
	cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
S
Steve French 已提交
2924
	if (rc)
2925 2926
		cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
			 rc);
L
Linus Torvalds 已提交
2927

2928
	cifs_buf_release(pSMB);
L
Linus Torvalds 已提交
2929 2930 2931 2932 2933 2934 2935 2936

	if (rc == -EAGAIN)
		goto createSymLinkRetry;

	return rc;
}

int
2937
CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
L
Linus Torvalds 已提交
2938
		       const char *fromName, const char *toName,
2939
		       const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949
{
	TRANSACTION2_SPI_REQ *pSMB = NULL;
	TRANSACTION2_SPI_RSP *pSMBr = NULL;
	char *data_offset;
	int name_len;
	int name_len_target;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, param_offset, offset, byte_count;

2950
	cifs_dbg(FYI, "In Create Hard link Unix style\n");
L
Linus Torvalds 已提交
2951 2952 2953 2954 2955 2956 2957
createHardLinkRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2958 2959
		name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
					      PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
2960 2961 2962
		name_len++;	/* trailing null */
		name_len *= 2;

2963
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974
		name_len = strnlen(toName, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, toName, name_len);
	}
	params = 6 + name_len;
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
2975
				InformationLevel) - 4;
L
Linus Torvalds 已提交
2976 2977 2978 2979 2980
	offset = param_offset + params;

	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len_target =
2981 2982
		    cifsConvertToUTF16((__le16 *) data_offset, fromName,
				       PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
2983 2984
		name_len_target++;	/* trailing null */
		name_len_target *= 2;
2985
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005
		name_len_target = strnlen(fromName, PATH_MAX);
		name_len_target++;	/* trailing null */
		strncpy(data_offset, fromName, name_len_target);
	}

	pSMB->MaxParameterCount = cpu_to_le16(2);
	/* BB find exact max on data count below from sess*/
	pSMB->MaxDataCount = cpu_to_le16(1000);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + name_len_target;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->DataCount = cpu_to_le16(name_len_target);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
	pSMB->Reserved4 = 0;
3006
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
3007 3008 3009
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3010
	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
S
Steve French 已提交
3011
	if (rc)
3012 3013
		cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
			 rc);
L
Linus Torvalds 已提交
3014 3015 3016 3017 3018 3019 3020 3021 3022

	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto createHardLinkRetry;

	return rc;
}

int
3023
CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
S
Steve French 已提交
3024 3025
		   const char *from_name, const char *to_name,
		   struct cifs_sb_info *cifs_sb)
L
Linus Torvalds 已提交
3026 3027 3028 3029 3030 3031 3032
{
	int rc = 0;
	NT_RENAME_REQ *pSMB = NULL;
	RENAME_RSP *pSMBr = NULL;
	int bytes_returned;
	int name_len, name_len2;
	__u16 count;
3033
	int remap = cifs_remap(cifs_sb);
L
Linus Torvalds 已提交
3034

3035
	cifs_dbg(FYI, "In CIFSCreateHardLink\n");
L
Linus Torvalds 已提交
3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052
winCreateHardLinkRetry:

	rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	pSMB->SearchAttributes =
	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
			ATTR_DIRECTORY);
	pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
	pSMB->ClusterCount = 0;

	pSMB->BufferFormat = 0x04;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
S
Steve French 已提交
3053 3054
		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
				       PATH_MAX, cifs_sb->local_nls, remap);
L
Linus Torvalds 已提交
3055 3056
		name_len++;	/* trailing null */
		name_len *= 2;
3057 3058 3059 3060

		/* protocol specifies ASCII buffer format (0x04) for unicode */
		pSMB->OldFileName[name_len] = 0x04;
		pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
L
Linus Torvalds 已提交
3061
		name_len2 =
3062
		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
S
Steve French 已提交
3063 3064
				       to_name, PATH_MAX, cifs_sb->local_nls,
				       remap);
L
Linus Torvalds 已提交
3065 3066
		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
		name_len2 *= 2;	/* convert to bytes */
3067
	} else {	/* BB improve the check for buffer overruns BB */
S
Steve French 已提交
3068
		name_len = strnlen(from_name, PATH_MAX);
L
Linus Torvalds 已提交
3069
		name_len++;	/* trailing null */
S
Steve French 已提交
3070 3071
		strncpy(pSMB->OldFileName, from_name, name_len);
		name_len2 = strnlen(to_name, PATH_MAX);
L
Linus Torvalds 已提交
3072 3073
		name_len2++;	/* trailing null */
		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
S
Steve French 已提交
3074
		strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
L
Linus Torvalds 已提交
3075 3076 3077 3078 3079
		name_len2++;	/* trailing null */
		name_len2++;	/* signature byte */
	}

	count = 1 /* string type byte */  + name_len + name_len2;
3080
	inc_rfc1001_len(pSMB, count);
L
Linus Torvalds 已提交
3081 3082 3083 3084
	pSMB->ByteCount = cpu_to_le16(count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3085
	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
S
Steve French 已提交
3086
	if (rc)
3087
		cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
S
Steve French 已提交
3088

L
Linus Torvalds 已提交
3089 3090 3091 3092 3093 3094 3095 3096
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto winCreateHardLinkRetry;

	return rc;
}

int
3097
CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3098
			const unsigned char *searchName, char **symlinkinfo,
3099
			const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
3100 3101 3102 3103 3104 3105 3106 3107
{
/* SMB_QUERY_FILE_UNIX_LINK */
	TRANSACTION2_QPI_REQ *pSMB = NULL;
	TRANSACTION2_QPI_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	int name_len;
	__u16 params, byte_count;
3108
	char *data_start;
L
Linus Torvalds 已提交
3109

3110
	cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
L
Linus Torvalds 已提交
3111 3112 3113 3114 3115 3116 3117 3118 3119

querySymLinkRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
3120 3121 3122
			cifsConvertToUTF16((__le16 *) pSMB->FileName,
					   searchName, PATH_MAX, nls_codepage,
					   remap);
L
Linus Torvalds 已提交
3123 3124
		name_len++;	/* trailing null */
		name_len *= 2;
3125
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
3126 3127 3128 3129 3130 3131 3132 3133
		name_len = strnlen(searchName, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, searchName, name_len);
	}

	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
3134
	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
L
Linus Torvalds 已提交
3135 3136 3137 3138 3139 3140
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
3141
	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
3142 3143 3144 3145 3146 3147 3148 3149 3150 3151
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
	pSMB->Reserved4 = 0;
3152
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
3153 3154 3155 3156 3157
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
3158
		cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
L
Linus Torvalds 已提交
3159 3160 3161 3162 3163
	} else {
		/* decode response */

		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
		/* BB also check enough total bytes returned */
3164
		if (rc || get_bcc(&pSMBr->hdr) < 2)
3165
			rc = -EIO;
L
Linus Torvalds 已提交
3166
		else {
3167
			bool is_unicode;
3168 3169 3170 3171
			u16 count = le16_to_cpu(pSMBr->t2.DataCount);

			data_start = ((char *) &pSMBr->hdr.Protocol) +
					   le16_to_cpu(pSMBr->t2.DataOffset);
L
Linus Torvalds 已提交
3172

3173 3174 3175 3176 3177
			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
				is_unicode = true;
			else
				is_unicode = false;

3178
			/* BB FIXME investigate remapping reserved chars here */
3179 3180
			*symlinkinfo = cifs_strndup_from_utf16(data_start,
					count, is_unicode, nls_codepage);
3181
			if (!*symlinkinfo)
3182
				rc = -ENOMEM;
L
Linus Torvalds 已提交
3183 3184 3185 3186 3187 3188 3189 3190
		}
	}
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto querySymLinkRetry;
	return rc;
}

3191 3192 3193 3194 3195 3196 3197 3198 3199 3200
/*
 *	Recent Windows versions now create symlinks more frequently
 *	and they use the "reparse point" mechanism below.  We can of course
 *	do symlinks nicely to Samba and other servers which support the
 *	CIFS Unix Extensions and we can also do SFU symlinks and "client only"
 *	"MF" symlinks optionally, but for recent Windows we really need to
 *	reenable the code below and fix the cifs_symlink callers to handle this.
 *	In the interim this code has been moved to its own config option so
 *	it is not compiled in by default until callers fixed up and more tested.
 */
L
Linus Torvalds 已提交
3201
int
3202 3203 3204
CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
		    __u16 fid, char **symlinkinfo,
		    const struct nls_table *nls_codepage)
L
Linus Torvalds 已提交
3205 3206 3207
{
	int rc = 0;
	int bytes_returned;
3208 3209
	struct smb_com_transaction_ioctl_req *pSMB;
	struct smb_com_transaction_ioctl_rsp *pSMBr;
3210 3211 3212
	bool is_unicode;
	unsigned int sub_len;
	char *sub_start;
3213 3214
	struct reparse_symlink_data *reparse_buf;
	struct reparse_posix_data *posix_buf;
3215 3216 3217 3218
	__u32 data_offset, data_count;
	char *end_of_smb;

	cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
L
Linus Torvalds 已提交
3219 3220 3221 3222 3223 3224 3225 3226 3227
	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	pSMB->TotalParameterCount = 0 ;
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le32(2);
	/* BB find exact data count max from sess structure BB */
3228
	pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
L
Linus Torvalds 已提交
3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245
	pSMB->MaxSetupCount = 4;
	pSMB->Reserved = 0;
	pSMB->ParameterOffset = 0;
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 4;
	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
	pSMB->IsFsctl = 1; /* FSCTL */
	pSMB->IsRootFlag = 0;
	pSMB->Fid = fid; /* file handle always le */
	pSMB->ByteCount = 0;

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
3246
		cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262
		goto qreparse_out;
	}

	data_offset = le32_to_cpu(pSMBr->DataOffset);
	data_count = le32_to_cpu(pSMBr->DataCount);
	if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
		/* BB also check enough total bytes returned */
		rc = -EIO;	/* bad smb */
		goto qreparse_out;
	}
	if (!data_count || (data_count > 2048)) {
		rc = -EIO;
		cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
		goto qreparse_out;
	}
	end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3263
	reparse_buf = (struct reparse_symlink_data *)
3264 3265 3266 3267
				((char *)&pSMBr->hdr.Protocol + data_offset);
	if ((char *)reparse_buf >= end_of_smb) {
		rc = -EIO;
		goto qreparse_out;
L
Linus Torvalds 已提交
3268
	}
3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299
	if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
		cifs_dbg(FYI, "NFS style reparse tag\n");
		posix_buf =  (struct reparse_posix_data *)reparse_buf;

		if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
			cifs_dbg(FYI, "unsupported file type 0x%llx\n",
				 le64_to_cpu(posix_buf->InodeType));
			rc = -EOPNOTSUPP;
			goto qreparse_out;
		}
		is_unicode = true;
		sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
		if (posix_buf->PathBuffer + sub_len > end_of_smb) {
			cifs_dbg(FYI, "reparse buf beyond SMB\n");
			rc = -EIO;
			goto qreparse_out;
		}
		*symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
				sub_len, is_unicode, nls_codepage);
		goto qreparse_out;
	} else if (reparse_buf->ReparseTag !=
			cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
		rc = -EOPNOTSUPP;
		goto qreparse_out;
	}

	/* Reparse tag is NTFS symlink */
	sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
				reparse_buf->PathBuffer;
	sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
	if (sub_start + sub_len > end_of_smb) {
3300 3301 3302 3303 3304 3305 3306 3307
		cifs_dbg(FYI, "reparse buf beyond SMB\n");
		rc = -EIO;
		goto qreparse_out;
	}
	if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
		is_unicode = true;
	else
		is_unicode = false;
S
Steve French 已提交
3308

3309 3310 3311 3312 3313
	/* BB FIXME investigate remapping reserved chars here */
	*symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
					       nls_codepage);
	if (!*symlinkinfo)
		rc = -ENOMEM;
L
Linus Torvalds 已提交
3314
qreparse_out:
3315
	cifs_buf_release(pSMB);
L
Linus Torvalds 已提交
3316

3317 3318 3319 3320
	/*
	 * Note: On -EAGAIN error only caller can retry on handle based calls
	 * since file handle passed in no longer valid.
	 */
L
Linus Torvalds 已提交
3321 3322 3323
	return rc;
}

3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341
int
CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
		    __u16 fid)
{
	int rc = 0;
	int bytes_returned;
	struct smb_com_transaction_compr_ioctl_req *pSMB;
	struct smb_com_transaction_ioctl_rsp *pSMBr;

	cifs_dbg(FYI, "Set compression for %u\n", fid);
	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);

	pSMB->TotalParameterCount = 0;
3342
	pSMB->TotalDataCount = cpu_to_le32(2);
3343 3344 3345 3346 3347
	pSMB->MaxParameterCount = 0;
	pSMB->MaxDataCount = 0;
	pSMB->MaxSetupCount = 4;
	pSMB->Reserved = 0;
	pSMB->ParameterOffset = 0;
3348
	pSMB->DataCount = cpu_to_le32(2);
3349 3350 3351 3352
	pSMB->DataOffset =
		cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
				compression_state) - 4);  /* 84 */
	pSMB->SetupCount = 4;
3353
	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3354
	pSMB->ParameterCount = 0;
3355
	pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
3356 3357 3358 3359
	pSMB->IsFsctl = 1; /* FSCTL */
	pSMB->IsRootFlag = 0;
	pSMB->Fid = fid; /* file handle always le */
	/* 3 byte pad, followed by 2 byte compress state */
3360
	pSMB->ByteCount = cpu_to_le16(5);
3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377
	inc_rfc1001_len(pSMB, 5);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc)
		cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);

	cifs_buf_release(pSMB);

	/*
	 * Note: On -EAGAIN error only caller can retry on handle based calls
	 * since file handle passed in no longer valid.
	 */
	return rc;
}


L
Linus Torvalds 已提交
3378 3379 3380
#ifdef CONFIG_CIFS_POSIX

/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
3381
static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
3382
			     struct cifs_posix_ace *cifs_ace)
L
Linus Torvalds 已提交
3383 3384
{
	/* u8 cifs fields do not need le conversion */
3385 3386 3387
	ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
	ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
	ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
3388 3389 3390 3391
/*
	cifs_dbg(FYI, "perm %d tag %d id %d\n",
		 ace->e_perm, ace->e_tag, ace->e_id);
*/
L
Linus Torvalds 已提交
3392 3393 3394 3395 3396

	return;
}

/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
3397 3398
static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
			       const int acl_type, const int size_of_data_area)
L
Linus Torvalds 已提交
3399 3400 3401 3402
{
	int size =  0;
	int i;
	__u16 count;
3403 3404
	struct cifs_posix_ace *pACE;
	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3405
	struct posix_acl_xattr_header *local_acl = (void *)trgt;
L
Linus Torvalds 已提交
3406 3407 3408 3409

	if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
		return -EOPNOTSUPP;

3410
	if (acl_type == ACL_TYPE_ACCESS) {
L
Linus Torvalds 已提交
3411 3412 3413 3414 3415
		count = le16_to_cpu(cifs_acl->access_entry_count);
		pACE = &cifs_acl->ace_array[0];
		size = sizeof(struct cifs_posix_acl);
		size += sizeof(struct cifs_posix_ace) * count;
		/* check if we would go beyond end of SMB */
S
Steve French 已提交
3416
		if (size_of_data_area < size) {
3417 3418
			cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
				 size_of_data_area, size);
L
Linus Torvalds 已提交
3419 3420
			return -EINVAL;
		}
3421
	} else if (acl_type == ACL_TYPE_DEFAULT) {
L
Linus Torvalds 已提交
3422 3423 3424 3425 3426 3427 3428 3429
		count = le16_to_cpu(cifs_acl->access_entry_count);
		size = sizeof(struct cifs_posix_acl);
		size += sizeof(struct cifs_posix_ace) * count;
/* skip past access ACEs to get to default ACEs */
		pACE = &cifs_acl->ace_array[count];
		count = le16_to_cpu(cifs_acl->default_entry_count);
		size += sizeof(struct cifs_posix_ace) * count;
		/* check if we would go beyond end of SMB */
S
Steve French 已提交
3430
		if (size_of_data_area < size)
L
Linus Torvalds 已提交
3431 3432 3433 3434 3435 3436 3437
			return -EINVAL;
	} else {
		/* illegal type */
		return -EINVAL;
	}

	size = posix_acl_xattr_size(count);
S
Steve French 已提交
3438
	if ((buflen == 0) || (local_acl == NULL)) {
3439
		/* used to query ACL EA size */
S
Steve French 已提交
3440
	} else if (size > buflen) {
L
Linus Torvalds 已提交
3441 3442
		return -ERANGE;
	} else /* buffer big enough */ {
3443 3444
		struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);

3445
		local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
3446
		for (i = 0; i < count ; i++) {
3447
			cifs_convert_ace(&ace[i], pACE);
3448
			pACE++;
L
Linus Torvalds 已提交
3449 3450 3451 3452 3453
		}
	}
	return size;
}

3454
static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3455
				     const struct posix_acl_xattr_entry *local_ace)
L
Linus Torvalds 已提交
3456 3457 3458
{
	__u16 rc = 0; /* 0 = ACL converted ok */

3459 3460
	cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
	cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
L
Linus Torvalds 已提交
3461
	/* BB is there a better way to handle the large uid? */
S
Steve French 已提交
3462
	if (local_ace->e_id == cpu_to_le32(-1)) {
L
Linus Torvalds 已提交
3463 3464
	/* Probably no need to le convert -1 on any arch but can not hurt */
		cifs_ace->cifs_uid = cpu_to_le64(-1);
3465
	} else
3466
		cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
3467 3468 3469 3470
/*
	cifs_dbg(FYI, "perm %d tag %d id %d\n",
		 ace->e_perm, ace->e_tag, ace->e_id);
*/
L
Linus Torvalds 已提交
3471 3472 3473 3474
	return rc;
}

/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
3475 3476
static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
			       const int buflen, const int acl_type)
L
Linus Torvalds 已提交
3477 3478
{
	__u16 rc = 0;
3479
	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3480
	struct posix_acl_xattr_header *local_acl = (void *)pACL;
3481
	struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
L
Linus Torvalds 已提交
3482 3483 3484
	int count;
	int i;

S
Steve French 已提交
3485
	if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
L
Linus Torvalds 已提交
3486 3487 3488
		return 0;

	count = posix_acl_xattr_count((size_t)buflen);
3489 3490
	cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
		 count, buflen, le32_to_cpu(local_acl->a_version));
S
Steve French 已提交
3491
	if (le32_to_cpu(local_acl->a_version) != 2) {
3492 3493
		cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
			 le32_to_cpu(local_acl->a_version));
L
Linus Torvalds 已提交
3494 3495 3496
		return 0;
	}
	cifs_acl->version = cpu_to_le16(1);
3497
	if (acl_type == ACL_TYPE_ACCESS) {
3498
		cifs_acl->access_entry_count = cpu_to_le16(count);
3499
		cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
3500
	} else if (acl_type == ACL_TYPE_DEFAULT) {
3501
		cifs_acl->default_entry_count = cpu_to_le16(count);
3502
		cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
3503
	} else {
3504
		cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
L
Linus Torvalds 已提交
3505 3506
		return 0;
	}
3507
	for (i = 0; i < count; i++) {
3508
		rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
S
Steve French 已提交
3509
		if (rc != 0) {
L
Linus Torvalds 已提交
3510 3511 3512 3513
			/* ACE not converted */
			break;
		}
	}
S
Steve French 已提交
3514
	if (rc == 0) {
L
Linus Torvalds 已提交
3515 3516 3517 3518 3519 3520 3521 3522
		rc = (__u16)(count * sizeof(struct cifs_posix_ace));
		rc += sizeof(struct cifs_posix_acl);
		/* BB add check to make sure ACL does not overflow SMB */
	}
	return rc;
}

int
3523
CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3524 3525 3526
		   const unsigned char *searchName,
		   char *acl_inf, const int buflen, const int acl_type,
		   const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
3527 3528 3529 3530 3531 3532 3533 3534
{
/* SMB_QUERY_POSIX_ACL */
	TRANSACTION2_QPI_REQ *pSMB = NULL;
	TRANSACTION2_QPI_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	int name_len;
	__u16 params, byte_count;
3535

3536
	cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
L
Linus Torvalds 已提交
3537 3538 3539 3540 3541 3542

queryAclRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		(void **) &pSMBr);
	if (rc)
		return rc;
3543

L
Linus Torvalds 已提交
3544 3545
	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
3546 3547 3548
			cifsConvertToUTF16((__le16 *) pSMB->FileName,
					   searchName, PATH_MAX, nls_codepage,
					   remap);
L
Linus Torvalds 已提交
3549 3550 3551 3552
		name_len++;     /* trailing null */
		name_len *= 2;
		pSMB->FileName[name_len] = 0;
		pSMB->FileName[name_len+1] = 0;
3553
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
3554 3555 3556 3557 3558 3559 3560 3561
		name_len = strnlen(searchName, PATH_MAX);
		name_len++;     /* trailing null */
		strncpy(pSMB->FileName, searchName, name_len);
	}

	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
3562
	/* BB find exact max data count below from sess structure BB */
L
Linus Torvalds 已提交
3563 3564 3565 3566 3567 3568 3569
	pSMB->MaxDataCount = cpu_to_le16(4000);
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset = cpu_to_le16(
3570 3571
		offsetof(struct smb_com_transaction2_qpi_req,
			 InformationLevel) - 4);
L
Linus Torvalds 已提交
3572 3573 3574 3575 3576 3577 3578 3579 3580 3581
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
	pSMB->Reserved4 = 0;
3582
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
3583 3584 3585 3586
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
3587
	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
L
Linus Torvalds 已提交
3588
	if (rc) {
3589
		cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
L
Linus Torvalds 已提交
3590 3591
	} else {
		/* decode response */
3592

L
Linus Torvalds 已提交
3593 3594
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
		/* BB also check enough total bytes returned */
3595
		if (rc || get_bcc(&pSMBr->hdr) < 2)
L
Linus Torvalds 已提交
3596 3597 3598 3599 3600 3601
			rc = -EIO;      /* bad smb */
		else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
			rc = cifs_copy_posix_acl(acl_inf,
				(char *)&pSMBr->hdr.Protocol+data_offset,
3602
				buflen, acl_type, count);
L
Linus Torvalds 已提交
3603 3604 3605 3606 3607 3608 3609 3610 3611
		}
	}
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto queryAclRetry;
	return rc;
}

int
3612
CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
3613 3614 3615 3616
		   const unsigned char *fileName,
		   const char *local_acl, const int buflen,
		   const int acl_type,
		   const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
3617 3618 3619 3620 3621 3622 3623 3624 3625
{
	struct smb_com_transaction2_spi_req *pSMB = NULL;
	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
	char *parm_data;
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count, data_count, param_offset, offset;

3626
	cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
L
Linus Torvalds 已提交
3627 3628
setAclRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3629
		      (void **) &pSMBr);
L
Linus Torvalds 已提交
3630 3631 3632 3633
	if (rc)
		return rc;
	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
3634 3635
			cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
					   PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
3636 3637
		name_len++;     /* trailing null */
		name_len *= 2;
3638
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
3639 3640 3641 3642 3643 3644
		name_len = strnlen(fileName, PATH_MAX);
		name_len++;     /* trailing null */
		strncpy(pSMB->FileName, fileName, name_len);
	}
	params = 6 + name_len;
	pSMB->MaxParameterCount = cpu_to_le16(2);
3645 3646
	/* BB find max SMB size from sess */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
3647 3648 3649 3650 3651 3652
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
3653
				InformationLevel) - 4;
L
Linus Torvalds 已提交
3654 3655 3656 3657 3658
	offset = param_offset + params;
	parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);

	/* convert to on the wire format for POSIX ACL */
3659
	data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
L
Linus Torvalds 已提交
3660

S
Steve French 已提交
3661
	if (data_count == 0) {
L
Linus Torvalds 已提交
3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675
		rc = -EOPNOTSUPP;
		goto setACLerrorExit;
	}
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
	byte_count = 3 /* pad */  + params + data_count;
	pSMB->DataCount = cpu_to_le16(data_count);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->Reserved4 = 0;
3676
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
3677 3678
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3679
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
S
Steve French 已提交
3680
	if (rc)
3681
		cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
L
Linus Torvalds 已提交
3682 3683 3684 3685 3686 3687 3688 3689

setACLerrorExit:
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto setAclRetry;
	return rc;
}

3690 3691
/* BB fix tabs in this function FIXME BB */
int
3692
CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
S
Steve French 已提交
3693
	       const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
3694
{
3695 3696 3697 3698 3699
	int rc = 0;
	struct smb_t2_qfi_req *pSMB = NULL;
	struct smb_t2_qfi_rsp *pSMBr = NULL;
	int bytes_returned;
	__u16 params, byte_count;
3700

3701
	cifs_dbg(FYI, "In GetExtAttr\n");
S
Steve French 已提交
3702 3703
	if (tcon == NULL)
		return -ENODEV;
3704 3705

GetExtAttrRetry:
S
Steve French 已提交
3706 3707 3708 3709
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
			(void **) &pSMBr);
	if (rc)
		return rc;
3710

S
Steve French 已提交
3711
	params = 2 /* level */ + 2 /* fid */;
S
Steve French 已提交
3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732
	pSMB->t2.TotalDataCount = 0;
	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
	/* BB find exact max data count below from sess structure BB */
	pSMB->t2.MaxDataCount = cpu_to_le16(4000);
	pSMB->t2.MaxSetupCount = 0;
	pSMB->t2.Reserved = 0;
	pSMB->t2.Flags = 0;
	pSMB->t2.Timeout = 0;
	pSMB->t2.Reserved2 = 0;
	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
					       Fid) - 4);
	pSMB->t2.DataCount = 0;
	pSMB->t2.DataOffset = 0;
	pSMB->t2.SetupCount = 1;
	pSMB->t2.Reserved3 = 0;
	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
	pSMB->Pad = 0;
3733
	pSMB->Fid = netfid;
3734
	inc_rfc1001_len(pSMB, byte_count);
S
Steve French 已提交
3735 3736 3737 3738 3739
	pSMB->t2.ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
3740
		cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
S
Steve French 已提交
3741 3742 3743 3744
	} else {
		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
		/* BB also check enough total bytes returned */
3745
		if (rc || get_bcc(&pSMBr->hdr) < 2)
S
Steve French 已提交
3746 3747 3748 3749 3750 3751 3752 3753 3754
			/* If rc should we check for EOPNOSUPP and
			   disable the srvino flag? or in caller? */
			rc = -EIO;      /* bad smb */
		else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
			struct file_chattr_info *pfinfo;
			/* BB Do we need a cast or hash here ? */
			if (count != 16) {
3755
				cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
S
Steve French 已提交
3756 3757 3758 3759 3760 3761
				rc = -EIO;
				goto GetExtAttrOut;
			}
			pfinfo = (struct file_chattr_info *)
				 (data_offset + (char *) &pSMBr->hdr.Protocol);
			*pExtAttrBits = le64_to_cpu(pfinfo->mode);
3762
			*pMask = le64_to_cpu(pfinfo->mask);
S
Steve French 已提交
3763 3764
		}
	}
3765
GetExtAttrOut:
S
Steve French 已提交
3766 3767 3768 3769
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto GetExtAttrRetry;
	return rc;
3770 3771 3772
}

#endif /* CONFIG_POSIX */
L
Linus Torvalds 已提交
3773

J
Jeff Layton 已提交
3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784
#ifdef CONFIG_CIFS_ACL
/*
 * Initialize NT TRANSACT SMB into small smb request buffer.  This assumes that
 * all NT TRANSACTS that we init here have total parm and data under about 400
 * bytes (to fit in small cifs buffer size), which is the case so far, it
 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
 * returned setup area) and MaxParameterCount (returned parms size) must be set
 * by caller
 */
static int
smb_init_nttransact(const __u16 sub_command, const int setup_count,
3785
		   const int parm_len, struct cifs_tcon *tcon,
J
Jeff Layton 已提交
3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799
		   void **ret_buf)
{
	int rc;
	__u32 temp_offset;
	struct smb_com_ntransact_req *pSMB;

	rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
				(void **)&pSMB);
	if (rc)
		return rc;
	*ret_buf = (void *)pSMB;
	pSMB->Reserved = 0;
	pSMB->TotalParameterCount = cpu_to_le32(parm_len);
	pSMB->TotalDataCount  = 0;
3800
	pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
J
Jeff Layton 已提交
3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->DataCount  = pSMB->TotalDataCount;
	temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
			(setup_count * 2) - 4 /* for rfc1001 length itself */;
	pSMB->ParameterOffset = cpu_to_le32(temp_offset);
	pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
	pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
	pSMB->SubCommand = cpu_to_le16(sub_command);
	return 0;
}

static int
validate_ntransact(char *buf, char **ppparm, char **ppdata,
		   __u32 *pparmlen, __u32 *pdatalen)
{
	char *end_of_smb;
	__u32 data_count, data_offset, parm_count, parm_offset;
	struct smb_com_ntransact_rsp *pSMBr;
3819
	u16 bcc;
J
Jeff Layton 已提交
3820 3821 3822 3823 3824 3825 3826 3827 3828

	*pdatalen = 0;
	*pparmlen = 0;

	if (buf == NULL)
		return -EINVAL;

	pSMBr = (struct smb_com_ntransact_rsp *)buf;

3829 3830
	bcc = get_bcc(&pSMBr->hdr);
	end_of_smb = 2 /* sizeof byte count */ + bcc +
J
Jeff Layton 已提交
3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842
			(char *)&pSMBr->ByteCount;

	data_offset = le32_to_cpu(pSMBr->DataOffset);
	data_count = le32_to_cpu(pSMBr->DataCount);
	parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
	parm_count = le32_to_cpu(pSMBr->ParameterCount);

	*ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
	*ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;

	/* should we also check that parm and data areas do not overlap? */
	if (*ppparm > end_of_smb) {
3843
		cifs_dbg(FYI, "parms start after end of smb\n");
J
Jeff Layton 已提交
3844 3845
		return -EINVAL;
	} else if (parm_count + *ppparm > end_of_smb) {
3846
		cifs_dbg(FYI, "parm end after end of smb\n");
J
Jeff Layton 已提交
3847 3848
		return -EINVAL;
	} else if (*ppdata > end_of_smb) {
3849
		cifs_dbg(FYI, "data starts after end of smb\n");
J
Jeff Layton 已提交
3850 3851
		return -EINVAL;
	} else if (data_count + *ppdata > end_of_smb) {
3852 3853 3854
		cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
			 *ppdata, data_count, (data_count + *ppdata),
			 end_of_smb, pSMBr);
J
Jeff Layton 已提交
3855
		return -EINVAL;
3856
	} else if (parm_count + data_count > bcc) {
3857
		cifs_dbg(FYI, "parm count and data count larger than SMB\n");
J
Jeff Layton 已提交
3858 3859 3860 3861 3862 3863 3864
		return -EINVAL;
	}
	*pdatalen = data_count;
	*pparmlen = parm_count;
	return 0;
}

3865 3866
/* Get Security Descriptor (by handle) from remote server for a file or dir */
int
3867
CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
S
Steve French 已提交
3868
		  struct cifs_ntsd **acl_inf, __u32 *pbuflen)
3869 3870 3871
{
	int rc = 0;
	int buf_type = 0;
S
Steve French 已提交
3872
	QUERY_SEC_DESC_REQ *pSMB;
3873
	struct kvec iov[1];
3874
	struct kvec rsp_iov;
3875

3876
	cifs_dbg(FYI, "GetCifsACL\n");
3877

S
Steve French 已提交
3878 3879 3880
	*pbuflen = 0;
	*acl_inf = NULL;

S
Steve French 已提交
3881
	rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892
			8 /* parm len */, tcon, (void **) &pSMB);
	if (rc)
		return rc;

	pSMB->MaxParameterCount = cpu_to_le32(4);
	/* BB TEST with big acls that might need to be e.g. larger than 16K */
	pSMB->MaxSetupCount = 0;
	pSMB->Fid = fid; /* file handle always le */
	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
				     CIFS_ACL_DACL);
	pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3893
	inc_rfc1001_len(pSMB, 11);
3894
	iov[0].iov_base = (char *)pSMB;
3895
	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
3896

3897
	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3898 3899
			  0, &rsp_iov);
	cifs_small_buf_release(pSMB);
3900
	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
3901
	if (rc) {
3902
		cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
3903
	} else {                /* decode response */
S
Steve French 已提交
3904
		__le32 *parm;
S
Steve French 已提交
3905 3906
		__u32 parm_len;
		__u32 acl_len;
3907
		struct smb_com_ntransact_rsp *pSMBr;
S
Steve French 已提交
3908
		char *pdata;
3909 3910

/* validate_nttransact */
3911
		rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
S
Steve French 已提交
3912
					&pdata, &parm_len, pbuflen);
S
Steve French 已提交
3913
		if (rc)
3914
			goto qsec_out;
3915
		pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
3916

3917 3918
		cifs_dbg(FYI, "smb %p parm %p data %p\n",
			 pSMBr, parm, *acl_inf);
3919 3920 3921

		if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
			rc = -EIO;      /* bad smb */
S
Steve French 已提交
3922
			*pbuflen = 0;
3923 3924 3925 3926 3927
			goto qsec_out;
		}

/* BB check that data area is minimum length and as big as acl_len */

3928
		acl_len = le32_to_cpu(*parm);
S
Steve French 已提交
3929
		if (acl_len != *pbuflen) {
3930 3931
			cifs_dbg(VFS, "acl length %d does not match %d\n",
				 acl_len, *pbuflen);
S
Steve French 已提交
3932 3933 3934
			if (*pbuflen > acl_len)
				*pbuflen = acl_len;
		}
3935

S
Steve French 已提交
3936 3937 3938 3939
		/* check if buffer is big enough for the acl
		   header followed by the smallest SID */
		if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
		    (*pbuflen >= 64 * 1024)) {
3940
			cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
S
Steve French 已提交
3941 3942 3943
			rc = -EINVAL;
			*pbuflen = 0;
		} else {
3944
			*acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
S
Steve French 已提交
3945 3946 3947 3948 3949
			if (*acl_inf == NULL) {
				*pbuflen = 0;
				rc = -ENOMEM;
			}
		}
3950 3951
	}
qsec_out:
3952
	free_rsp_buf(buf_type, rsp_iov.iov_base);
3953 3954
	return rc;
}
3955 3956

int
3957
CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
3958
			struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
3959 3960 3961 3962 3963
{
	__u16 byte_count, param_count, data_count, param_offset, data_offset;
	int rc = 0;
	int bytes_returned = 0;
	SET_SEC_DESC_REQ *pSMB = NULL;
3964
	void *pSMBr;
3965 3966

setCifsAclRetry:
3967
	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
3968
	if (rc)
3969
		return rc;
3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993

	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;

	param_count = 8;
	param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
	data_count = acllen;
	data_offset = param_offset + param_count;
	byte_count = 3 /* pad */  + param_count;

	pSMB->DataCount = cpu_to_le32(data_count);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->MaxParameterCount = cpu_to_le32(4);
	pSMB->MaxDataCount = cpu_to_le32(16384);
	pSMB->ParameterCount = cpu_to_le32(param_count);
	pSMB->ParameterOffset = cpu_to_le32(param_offset);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->DataOffset = cpu_to_le32(data_offset);
	pSMB->SetupCount = 0;
	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
	pSMB->ByteCount = cpu_to_le16(byte_count+data_count);

	pSMB->Fid = fid; /* file handle always le */
	pSMB->Reserved2 = 0;
3994
	pSMB->AclFlags = cpu_to_le32(aclflag);
3995 3996

	if (pntsd && acllen) {
3997 3998
		memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
				data_offset, pntsd, acllen);
3999
		inc_rfc1001_len(pSMB, byte_count + data_count);
4000
	} else
4001
		inc_rfc1001_len(pSMB, byte_count);
4002 4003 4004 4005

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
		(struct smb_hdr *) pSMBr, &bytes_returned, 0);

4006 4007
	cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
		 bytes_returned, rc);
4008
	if (rc)
4009
		cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
4010 4011 4012 4013 4014 4015 4016 4017
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto setCifsAclRetry;

	return (rc);
}

J
Jeff Layton 已提交
4018
#endif /* CONFIG_CIFS_ACL */
4019

4020 4021
/* Legacy Query Path Information call for lookup to old servers such
   as Win9x/WinME */
4022 4023 4024 4025
int
SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
		    const char *search_name, FILE_ALL_INFO *data,
		    const struct nls_table *nls_codepage, int remap)
4026
{
S
Steve French 已提交
4027 4028
	QUERY_INFORMATION_REQ *pSMB;
	QUERY_INFORMATION_RSP *pSMBr;
4029 4030 4031 4032
	int rc = 0;
	int bytes_returned;
	int name_len;

4033
	cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
4034 4035
QInfRetry:
	rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
4036
		      (void **) &pSMBr);
4037 4038 4039 4040 4041
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
4042
			cifsConvertToUTF16((__le16 *) pSMB->FileName,
4043
					   search_name, PATH_MAX, nls_codepage,
4044
					   remap);
4045 4046
		name_len++;     /* trailing null */
		name_len *= 2;
4047
	} else {
4048
		name_len = strnlen(search_name, PATH_MAX);
4049
		name_len++;     /* trailing null */
4050
		strncpy(pSMB->FileName, search_name, name_len);
4051 4052
	}
	pSMB->BufferFormat = 0x04;
4053
	name_len++; /* account for buffer type byte */
4054
	inc_rfc1001_len(pSMB, (__u16)name_len);
4055 4056 4057
	pSMB->ByteCount = cpu_to_le16(name_len);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4058
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4059
	if (rc) {
4060
		cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
4061
	} else if (data) {
4062 4063
		struct timespec ts;
		__u32 time = le32_to_cpu(pSMBr->last_write_time);
S
Steve French 已提交
4064 4065

		/* decode response */
4066
		/* BB FIXME - add time zone adjustment BB */
4067
		memset(data, 0, sizeof(FILE_ALL_INFO));
4068 4069 4070
		ts.tv_nsec = 0;
		ts.tv_sec = time;
		/* decode time fields */
4071 4072 4073 4074
		data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
		data->LastWriteTime = data->ChangeTime;
		data->LastAccessTime = 0;
		data->AllocationSize =
4075
			cpu_to_le64(le32_to_cpu(pSMBr->size));
4076 4077
		data->EndOfFile = data->AllocationSize;
		data->Attributes =
4078
			cpu_to_le32(le16_to_cpu(pSMBr->attr));
4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089
	} else
		rc = -EIO; /* bad buffer passed in */

	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto QInfRetry;

	return rc;
}

4090
int
4091
CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128
		 u16 netfid, FILE_ALL_INFO *pFindData)
{
	struct smb_t2_qfi_req *pSMB = NULL;
	struct smb_t2_qfi_rsp *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	__u16 params, byte_count;

QFileInfoRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	params = 2 /* level */ + 2 /* fid */;
	pSMB->t2.TotalDataCount = 0;
	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
	/* BB find exact max data count below from sess structure BB */
	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
	pSMB->t2.MaxSetupCount = 0;
	pSMB->t2.Reserved = 0;
	pSMB->t2.Flags = 0;
	pSMB->t2.Timeout = 0;
	pSMB->t2.Reserved2 = 0;
	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
					       Fid) - 4);
	pSMB->t2.DataCount = 0;
	pSMB->t2.DataOffset = 0;
	pSMB->t2.SetupCount = 1;
	pSMB->t2.Reserved3 = 0;
	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
	pSMB->Pad = 0;
	pSMB->Fid = netfid;
4129
	inc_rfc1001_len(pSMB, byte_count);
4130
	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
4131

4132 4133 4134
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
4135
		cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
4136 4137
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4138

4139 4140
		if (rc) /* BB add auto retry on EOPNOTSUPP? */
			rc = -EIO;
4141
		else if (get_bcc(&pSMBr->hdr) < 40)
4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153
			rc = -EIO;	/* bad smb */
		else if (pFindData) {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			memcpy((char *) pFindData,
			       (char *) &pSMBr->hdr.Protocol +
			       data_offset, sizeof(FILE_ALL_INFO));
		} else
		    rc = -ENOMEM;
	}
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto QFileInfoRetry;
4154

4155 4156
	return rc;
}
4157

L
Linus Torvalds 已提交
4158
int
4159
CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
4160
		 const char *search_name, FILE_ALL_INFO *data,
4161
		 int legacy /* old style infolevel */,
4162
		 const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
4163
{
4164
	/* level 263 SMB_QUERY_FILE_ALL_INFO */
L
Linus Torvalds 已提交
4165 4166 4167 4168 4169 4170 4171
	TRANSACTION2_QPI_REQ *pSMB = NULL;
	TRANSACTION2_QPI_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	int name_len;
	__u16 params, byte_count;

4172
	/* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
L
Linus Torvalds 已提交
4173 4174 4175 4176 4177 4178 4179 4180
QPathInfoRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
4181
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
4182
				       PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
4183 4184
		name_len++;	/* trailing null */
		name_len *= 2;
4185
	} else {	/* BB improve the check for buffer overruns BB */
4186
		name_len = strnlen(search_name, PATH_MAX);
L
Linus Torvalds 已提交
4187
		name_len++;	/* trailing null */
4188
		strncpy(pSMB->FileName, search_name, name_len);
L
Linus Torvalds 已提交
4189 4190
	}

4191
	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
L
Linus Torvalds 已提交
4192 4193
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
4194 4195
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(4000);
L
Linus Torvalds 已提交
4196 4197 4198 4199 4200 4201
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
4202
	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
4203 4204 4205 4206 4207 4208 4209 4210
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
S
Steve French 已提交
4211
	if (legacy)
4212 4213 4214
		pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
	else
		pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
L
Linus Torvalds 已提交
4215
	pSMB->Reserved4 = 0;
4216
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
4217 4218 4219 4220 4221
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
4222
		cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
L
Linus Torvalds 已提交
4223 4224 4225
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

4226 4227
		if (rc) /* BB add auto retry on EOPNOTSUPP? */
			rc = -EIO;
4228
		else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
L
Linus Torvalds 已提交
4229
			rc = -EIO;	/* bad smb */
4230
		else if (legacy && get_bcc(&pSMBr->hdr) < 24)
4231 4232
			rc = -EIO;  /* 24 or 26 expected but we do not read
					last field */
4233
		else if (data) {
4234
			int size;
L
Linus Torvalds 已提交
4235
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
S
Steve French 已提交
4236

4237 4238 4239 4240 4241 4242
			/*
			 * On legacy responses we do not read the last field,
			 * EAsize, fortunately since it varies by subdialect and
			 * also note it differs on Set vs Get, ie two bytes or 4
			 * bytes depending but we don't care here.
			 */
S
Steve French 已提交
4243
			if (legacy)
4244 4245 4246
				size = sizeof(FILE_INFO_STANDARD);
			else
				size = sizeof(FILE_ALL_INFO);
4247
			memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
4248
			       data_offset, size);
L
Linus Torvalds 已提交
4249 4250 4251 4252 4253 4254 4255 4256 4257 4258
		} else
		    rc = -ENOMEM;
	}
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto QPathInfoRetry;

	return rc;
}

4259
int
4260
CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297
		 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
{
	struct smb_t2_qfi_req *pSMB = NULL;
	struct smb_t2_qfi_rsp *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	__u16 params, byte_count;

UnixQFileInfoRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	params = 2 /* level */ + 2 /* fid */;
	pSMB->t2.TotalDataCount = 0;
	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
	/* BB find exact max data count below from sess structure BB */
	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
	pSMB->t2.MaxSetupCount = 0;
	pSMB->t2.Reserved = 0;
	pSMB->t2.Flags = 0;
	pSMB->t2.Timeout = 0;
	pSMB->t2.Reserved2 = 0;
	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
					       Fid) - 4);
	pSMB->t2.DataCount = 0;
	pSMB->t2.DataOffset = 0;
	pSMB->t2.SetupCount = 1;
	pSMB->t2.Reserved3 = 0;
	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
	pSMB->Pad = 0;
	pSMB->Fid = netfid;
4298
	inc_rfc1001_len(pSMB, byte_count);
4299
	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
4300 4301 4302 4303

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
4304
		cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
4305 4306 4307
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

4308
		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4309
			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326
			rc = -EIO;	/* bad smb */
		} else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			memcpy((char *) pFindData,
			       (char *) &pSMBr->hdr.Protocol +
			       data_offset,
			       sizeof(FILE_UNIX_BASIC_INFO));
		}
	}

	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto UnixQFileInfoRetry;

	return rc;
}

L
Linus Torvalds 已提交
4327
int
4328
CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
L
Linus Torvalds 已提交
4329
		     const unsigned char *searchName,
4330
		     FILE_UNIX_BASIC_INFO *pFindData,
4331
		     const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
4332 4333 4334 4335 4336 4337 4338 4339 4340
{
/* SMB_QUERY_FILE_UNIX_BASIC */
	TRANSACTION2_QPI_REQ *pSMB = NULL;
	TRANSACTION2_QPI_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned = 0;
	int name_len;
	__u16 params, byte_count;

4341
	cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
L
Linus Torvalds 已提交
4342 4343 4344 4345 4346 4347 4348 4349
UnixQPathInfoRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
4350 4351
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
				       PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
4352 4353
		name_len++;	/* trailing null */
		name_len *= 2;
4354
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
4355 4356 4357 4358 4359
		name_len = strnlen(searchName, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, searchName, name_len);
	}

4360
	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
L
Linus Torvalds 已提交
4361 4362 4363
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
	/* BB find exact max SMB PDU from sess structure BB */
4364
	pSMB->MaxDataCount = cpu_to_le16(4000);
L
Linus Torvalds 已提交
4365 4366 4367 4368 4369 4370
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
4371
	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
4372 4373 4374 4375 4376 4377 4378 4379 4380 4381
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
	pSMB->Reserved4 = 0;
4382
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
4383 4384 4385 4386 4387
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
4388
		cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
L
Linus Torvalds 已提交
4389 4390 4391
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

4392
		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
4393
			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
L
Linus Torvalds 已提交
4394 4395 4396 4397 4398 4399
			rc = -EIO;	/* bad smb */
		} else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			memcpy((char *) pFindData,
			       (char *) &pSMBr->hdr.Protocol +
			       data_offset,
S
Steve French 已提交
4400
			       sizeof(FILE_UNIX_BASIC_INFO));
L
Linus Torvalds 已提交
4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411
		}
	}
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto UnixQPathInfoRetry;

	return rc;
}

/* xid, tcon, searchName and codepage are input parms, rest are returned */
int
4412
CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
4413
	      const char *searchName, struct cifs_sb_info *cifs_sb,
4414
	      __u16 *pnetfid, __u16 search_flags,
4415
	      struct cifs_search_info *psrch_inf, bool msearch)
L
Linus Torvalds 已提交
4416 4417 4418 4419
{
/* level 257 SMB_ */
	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
S
Steve French 已提交
4420
	T2_FFIRST_RSP_PARMS *parms;
L
Linus Torvalds 已提交
4421 4422
	int rc = 0;
	int bytes_returned = 0;
4423
	int name_len, remap;
L
Linus Torvalds 已提交
4424
	__u16 params, byte_count;
4425
	struct nls_table *nls_codepage;
L
Linus Torvalds 已提交
4426

4427
	cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
L
Linus Torvalds 已提交
4428 4429 4430 4431 4432 4433 4434

findFirstRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

4435
	nls_codepage = cifs_sb->local_nls;
4436
	remap = cifs_remap(cifs_sb);
4437

L
Linus Torvalds 已提交
4438 4439
	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
4440 4441
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
				       PATH_MAX, nls_codepage, remap);
4442 4443 4444
		/* We can not add the asterik earlier in case
		it got remapped to 0xF03A as if it were part of the
		directory name instead of a wildcard */
L
Linus Torvalds 已提交
4445
		name_len *= 2;
4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456
		if (msearch) {
			pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
			pSMB->FileName[name_len+1] = 0;
			pSMB->FileName[name_len+2] = '*';
			pSMB->FileName[name_len+3] = 0;
			name_len += 4; /* now the trailing null */
			/* null terminate just in case */
			pSMB->FileName[name_len] = 0;
			pSMB->FileName[name_len+1] = 0;
			name_len += 2;
		}
L
Linus Torvalds 已提交
4457 4458 4459
	} else {	/* BB add check for overrun of SMB buf BB */
		name_len = strnlen(searchName, PATH_MAX);
/* BB fix here and in unicode clause above ie
S
Steve French 已提交
4460
		if (name_len > buffersize-header)
L
Linus Torvalds 已提交
4461 4462
			free buffer exit; BB */
		strncpy(pSMB->FileName, searchName, name_len);
4463 4464 4465 4466 4467 4468
		if (msearch) {
			pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
			pSMB->FileName[name_len+1] = '*';
			pSMB->FileName[name_len+2] = 0;
			name_len += 3;
		}
L
Linus Torvalds 已提交
4469 4470 4471 4472 4473
	}

	params = 12 + name_len /* includes null */ ;
	pSMB->TotalDataCount = 0;	/* no EAs */
	pSMB->MaxParameterCount = cpu_to_le16(10);
4474
	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
L
Linus Torvalds 已提交
4475 4476 4477 4478 4479 4480 4481 4482 4483
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(
4484 4485
	      offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
		- 4);
L
Linus Torvalds 已提交
4486 4487 4488 4489 4490 4491 4492 4493
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
	pSMB->SearchAttributes =
	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
			ATTR_DIRECTORY);
4494
	pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4495
	pSMB->SearchFlags = cpu_to_le16(search_flags);
L
Linus Torvalds 已提交
4496 4497 4498 4499
	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);

	/* BB what should we set StorageType to? Does it matter? BB */
	pSMB->SearchStorageType = 0;
4500
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
4501 4502 4503 4504
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4505
	cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
L
Linus Torvalds 已提交
4506

4507 4508
	if (rc) {/* BB add logic to retry regular search if Unix search
			rejected unexpectedly by server */
L
Linus Torvalds 已提交
4509
		/* BB Add code to handle unsupported level rc */
4510
		cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
4511

4512
		cifs_buf_release(pSMB);
L
Linus Torvalds 已提交
4513 4514 4515 4516 4517 4518 4519 4520

		/* BB eventually could optimize out free and realloc of buf */
		/*    for this case */
		if (rc == -EAGAIN)
			goto findFirstRetry;
	} else { /* decode response */
		/* BB remember to free buffer if error BB */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
S
Steve French 已提交
4521
		if (rc == 0) {
4522 4523
			unsigned int lnoff;

L
Linus Torvalds 已提交
4524
			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4525
				psrch_inf->unicode = true;
L
Linus Torvalds 已提交
4526
			else
4527
				psrch_inf->unicode = false;
L
Linus Torvalds 已提交
4528 4529

			psrch_inf->ntwrk_buf_start = (char *)pSMBr;
4530
			psrch_inf->smallBuf = 0;
4531 4532
			psrch_inf->srch_entries_start =
				(char *) &pSMBr->hdr.Protocol +
L
Linus Torvalds 已提交
4533 4534 4535 4536
					le16_to_cpu(pSMBr->t2.DataOffset);
			parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
			       le16_to_cpu(pSMBr->t2.ParameterOffset));

S
Steve French 已提交
4537
			if (parms->EndofSearch)
4538
				psrch_inf->endOfSearch = true;
L
Linus Torvalds 已提交
4539
			else
4540
				psrch_inf->endOfSearch = false;
L
Linus Torvalds 已提交
4541

4542 4543
			psrch_inf->entries_in_buffer =
					le16_to_cpu(parms->SearchCount);
4544
			psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
L
Linus Torvalds 已提交
4545
				psrch_inf->entries_in_buffer;
4546
			lnoff = le16_to_cpu(parms->LastNameOffset);
4547
			if (CIFSMaxBufSize < lnoff) {
4548
				cifs_dbg(VFS, "ignoring corrupt resume name\n");
4549 4550 4551 4552
				psrch_inf->last_entry = NULL;
				return rc;
			}

4553
			psrch_inf->last_entry = psrch_inf->srch_entries_start +
4554 4555
							lnoff;

4556 4557
			if (pnetfid)
				*pnetfid = parms->SearchHandle;
L
Linus Torvalds 已提交
4558 4559 4560 4561 4562 4563 4564 4565
		} else {
			cifs_buf_release(pSMB);
		}
	}

	return rc;
}

4566 4567 4568
int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
		 __u16 searchHandle, __u16 search_flags,
		 struct cifs_search_info *psrch_inf)
L
Linus Torvalds 已提交
4569 4570 4571
{
	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
S
Steve French 已提交
4572
	T2_FNEXT_RSP_PARMS *parms;
L
Linus Torvalds 已提交
4573 4574
	char *response_data;
	int rc = 0;
4575 4576
	int bytes_returned;
	unsigned int name_len;
L
Linus Torvalds 已提交
4577 4578
	__u16 params, byte_count;

4579
	cifs_dbg(FYI, "In FindNext\n");
L
Linus Torvalds 已提交
4580

4581
	if (psrch_inf->endOfSearch)
L
Linus Torvalds 已提交
4582 4583 4584 4585 4586 4587 4588
		return -ENOENT;

	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		(void **) &pSMBr);
	if (rc)
		return rc;

4589
	params = 14; /* includes 2 bytes of null string, converted to LE below*/
L
Linus Torvalds 已提交
4590 4591 4592
	byte_count = 0;
	pSMB->TotalDataCount = 0;       /* no EAs */
	pSMB->MaxParameterCount = cpu_to_le16(8);
4593
	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
L
Linus Torvalds 已提交
4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset =  cpu_to_le16(
	      offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
	pSMB->SearchHandle = searchHandle;      /* always kept as le */
	pSMB->SearchCount =
S
Steve French 已提交
4608
		cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
L
Linus Torvalds 已提交
4609 4610
	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
	pSMB->ResumeKey = psrch_inf->resume_key;
4611
	pSMB->SearchFlags = cpu_to_le16(search_flags);
L
Linus Torvalds 已提交
4612 4613 4614

	name_len = psrch_inf->resume_name_len;
	params += name_len;
S
Steve French 已提交
4615
	if (name_len < PATH_MAX) {
L
Linus Torvalds 已提交
4616 4617
		memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
		byte_count += name_len;
4618 4619 4620
		/* 14 byte parm len above enough for 2 byte null terminator */
		pSMB->ResumeFileName[name_len] = 0;
		pSMB->ResumeFileName[name_len+1] = 0;
L
Linus Torvalds 已提交
4621 4622 4623 4624 4625 4626 4627
	} else {
		rc = -EINVAL;
		goto FNext2_err_exit;
	}
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
4628
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
4629
	pSMB->ByteCount = cpu_to_le16(byte_count);
4630

L
Linus Torvalds 已提交
4631 4632
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
4633
	cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
L
Linus Torvalds 已提交
4634 4635
	if (rc) {
		if (rc == -EBADF) {
4636
			psrch_inf->endOfSearch = true;
J
Jeff Layton 已提交
4637
			cifs_buf_release(pSMB);
4638
			rc = 0; /* search probably was closed at end of search*/
L
Linus Torvalds 已提交
4639
		} else
4640
			cifs_dbg(FYI, "FindNext returned = %d\n", rc);
L
Linus Torvalds 已提交
4641 4642
	} else {                /* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4643

S
Steve French 已提交
4644
		if (rc == 0) {
4645 4646
			unsigned int lnoff;

L
Linus Torvalds 已提交
4647 4648
			/* BB fixme add lock for file (srch_info) struct here */
			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4649
				psrch_inf->unicode = true;
L
Linus Torvalds 已提交
4650
			else
4651
				psrch_inf->unicode = false;
L
Linus Torvalds 已提交
4652 4653 4654 4655 4656
			response_data = (char *) &pSMBr->hdr.Protocol +
			       le16_to_cpu(pSMBr->t2.ParameterOffset);
			parms = (T2_FNEXT_RSP_PARMS *)response_data;
			response_data = (char *)&pSMBr->hdr.Protocol +
				le16_to_cpu(pSMBr->t2.DataOffset);
S
Steve French 已提交
4657
			if (psrch_inf->smallBuf)
4658 4659 4660 4661
				cifs_small_buf_release(
					psrch_inf->ntwrk_buf_start);
			else
				cifs_buf_release(psrch_inf->ntwrk_buf_start);
L
Linus Torvalds 已提交
4662 4663
			psrch_inf->srch_entries_start = response_data;
			psrch_inf->ntwrk_buf_start = (char *)pSMB;
4664
			psrch_inf->smallBuf = 0;
S
Steve French 已提交
4665
			if (parms->EndofSearch)
4666
				psrch_inf->endOfSearch = true;
L
Linus Torvalds 已提交
4667
			else
4668
				psrch_inf->endOfSearch = false;
4669 4670
			psrch_inf->entries_in_buffer =
						le16_to_cpu(parms->SearchCount);
L
Linus Torvalds 已提交
4671 4672
			psrch_inf->index_of_last_entry +=
				psrch_inf->entries_in_buffer;
4673
			lnoff = le16_to_cpu(parms->LastNameOffset);
4674
			if (CIFSMaxBufSize < lnoff) {
4675
				cifs_dbg(VFS, "ignoring corrupt resume name\n");
4676 4677 4678 4679 4680 4681
				psrch_inf->last_entry = NULL;
				return rc;
			} else
				psrch_inf->last_entry =
					psrch_inf->srch_entries_start + lnoff;

4682 4683
/*  cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
    psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
L
Linus Torvalds 已提交
4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701

			/* BB fixme add unlock here */
		}

	}

	/* BB On error, should we leave previous search buf (and count and
	last entry fields) intact or free the previous one? */

	/* Note: On -EAGAIN error only caller can retry on handle based calls
	since file handle passed in no longer valid */
FNext2_err_exit:
	if (rc != 0)
		cifs_buf_release(pSMB);
	return rc;
}

int
4702
CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
4703
	      const __u16 searchHandle)
L
Linus Torvalds 已提交
4704 4705 4706 4707
{
	int rc = 0;
	FINDCLOSE_REQ *pSMB = NULL;

4708
	cifs_dbg(FYI, "In CIFSSMBFindClose\n");
L
Linus Torvalds 已提交
4709 4710 4711 4712
	rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);

	/* no sense returning error if session restarted
		as file handle has been closed */
S
Steve French 已提交
4713
	if (rc == -EAGAIN)
L
Linus Torvalds 已提交
4714 4715 4716 4717 4718 4719
		return 0;
	if (rc)
		return rc;

	pSMB->FileID = searchHandle;
	pSMB->ByteCount = 0;
4720
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
4721
	cifs_small_buf_release(pSMB);
S
Steve French 已提交
4722
	if (rc)
4723
		cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
S
Steve French 已提交
4724

4725
	cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
L
Linus Torvalds 已提交
4726 4727 4728 4729 4730 4731 4732 4733 4734

	/* Since session is dead, search handle closed on server already */
	if (rc == -EAGAIN)
		rc = 0;

	return rc;
}

int
4735
CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
4736
		      const char *search_name, __u64 *inode_number,
4737
		      const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
4738 4739 4740 4741 4742 4743 4744
{
	int rc = 0;
	TRANSACTION2_QPI_REQ *pSMB = NULL;
	TRANSACTION2_QPI_RSP *pSMBr = NULL;
	int name_len, bytes_returned;
	__u16 params, byte_count;

4745
	cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
S
Steve French 已提交
4746
	if (tcon == NULL)
4747
		return -ENODEV;
L
Linus Torvalds 已提交
4748 4749 4750

GetInodeNumberRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4751
		      (void **) &pSMBr);
L
Linus Torvalds 已提交
4752 4753 4754 4755 4756
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
4757
			cifsConvertToUTF16((__le16 *) pSMB->FileName,
4758
					   search_name, PATH_MAX, nls_codepage,
4759
					   remap);
L
Linus Torvalds 已提交
4760 4761
		name_len++;     /* trailing null */
		name_len *= 2;
4762
	} else {	/* BB improve the check for buffer overruns BB */
4763
		name_len = strnlen(search_name, PATH_MAX);
L
Linus Torvalds 已提交
4764
		name_len++;     /* trailing null */
4765
		strncpy(pSMB->FileName, search_name, name_len);
L
Linus Torvalds 已提交
4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778
	}

	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
	/* BB find exact max data count below from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(4000);
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
4779
		struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
4780 4781 4782 4783 4784 4785 4786 4787 4788 4789
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
	pSMB->Reserved4 = 0;
4790
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
4791 4792 4793 4794 4795
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
4796
		cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
L
Linus Torvalds 已提交
4797 4798 4799 4800
	} else {
		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
		/* BB also check enough total bytes returned */
4801
		if (rc || get_bcc(&pSMBr->hdr) < 2)
L
Linus Torvalds 已提交
4802 4803 4804
			/* If rc should we check for EOPNOSUPP and
			disable the srvino flag? or in caller? */
			rc = -EIO;      /* bad smb */
4805
		else {
L
Linus Torvalds 已提交
4806 4807
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
4808
			struct file_internal_info *pfinfo;
L
Linus Torvalds 已提交
4809
			/* BB Do we need a cast or hash here ? */
S
Steve French 已提交
4810
			if (count < 8) {
4811
				cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
L
Linus Torvalds 已提交
4812 4813 4814 4815 4816
				rc = -EIO;
				goto GetInodeNumOut;
			}
			pfinfo = (struct file_internal_info *)
				(data_offset + (char *) &pSMBr->hdr.Protocol);
4817
			*inode_number = le64_to_cpu(pfinfo->UniqueId);
L
Linus Torvalds 已提交
4818 4819 4820 4821 4822 4823 4824 4825 4826 4827
		}
	}
GetInodeNumOut:
	cifs_buf_release(pSMB);
	if (rc == -EAGAIN)
		goto GetInodeNumberRetry;
	return rc;
}

int
4828
CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
4829
		const char *search_name, struct dfs_info3_param **target_nodes,
S
Steve French 已提交
4830
		unsigned int *num_of_nodes,
4831
		const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
4832 4833 4834 4835 4836 4837 4838 4839
{
/* TRANS2_GET_DFS_REFERRAL */
	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
	TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	int name_len;
	__u16 params, byte_count;
S
Steve French 已提交
4840 4841
	*num_of_nodes = 0;
	*target_nodes = NULL;
L
Linus Torvalds 已提交
4842

4843
	cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
A
Aurelien Aptel 已提交
4844
	if (ses == NULL || ses->tcon_ipc == NULL)
L
Linus Torvalds 已提交
4845
		return -ENODEV;
A
Aurelien Aptel 已提交
4846

L
Linus Torvalds 已提交
4847
getDFSRetry:
A
Aurelien Aptel 已提交
4848
	rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
L
Linus Torvalds 已提交
4849 4850 4851
		      (void **) &pSMBr);
	if (rc)
		return rc;
4852 4853

	/* server pointer checked in called function,
4854
	but should never be null here anyway */
4855
	pSMB->hdr.Mid = get_next_mid(ses->server);
A
Aurelien Aptel 已提交
4856
	pSMB->hdr.Tid = ses->tcon_ipc->tid;
L
Linus Torvalds 已提交
4857
	pSMB->hdr.Uid = ses->Suid;
4858
	if (ses->capabilities & CAP_STATUS32)
L
Linus Torvalds 已提交
4859
		pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
4860
	if (ses->capabilities & CAP_DFS)
L
Linus Torvalds 已提交
4861 4862 4863 4864 4865
		pSMB->hdr.Flags2 |= SMBFLG2_DFS;

	if (ses->capabilities & CAP_UNICODE) {
		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
		name_len =
4866
		    cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4867
				       search_name, PATH_MAX, nls_codepage,
4868
				       remap);
L
Linus Torvalds 已提交
4869 4870
		name_len++;	/* trailing null */
		name_len *= 2;
4871
	} else {	/* BB improve the check for buffer overruns BB */
4872
		name_len = strnlen(search_name, PATH_MAX);
L
Linus Torvalds 已提交
4873
		name_len++;	/* trailing null */
4874
		strncpy(pSMB->RequestFileName, search_name, name_len);
L
Linus Torvalds 已提交
4875 4876
	}

4877
	if (ses->server->sign)
4878
		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
S
Steve French 已提交
4879

4880
	pSMB->hdr.Uid = ses->Suid;
S
Steve French 已提交
4881

L
Linus Torvalds 已提交
4882 4883 4884 4885 4886
	params = 2 /* level */  + name_len /*includes null */ ;
	pSMB->TotalDataCount = 0;
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->MaxParameterCount = 0;
4887 4888
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(4000);
L
Linus Torvalds 已提交
4889 4890 4891 4892 4893 4894
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
4895
	  struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
L
Linus Torvalds 已提交
4896 4897 4898 4899 4900 4901 4902
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
	byte_count = params + 3 /* pad */ ;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->MaxReferralLevel = cpu_to_le16(3);
4903
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
4904 4905 4906 4907 4908
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
4909
		cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
S
Steve French 已提交
4910 4911 4912
		goto GetDFSRefExit;
	}
	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
L
Linus Torvalds 已提交
4913

S
Steve French 已提交
4914
	/* BB Also check if enough total bytes returned? */
4915
	if (rc || get_bcc(&pSMBr->hdr) < 17) {
S
Steve French 已提交
4916
		rc = -EIO;      /* bad smb */
4917 4918
		goto GetDFSRefExit;
	}
S
Steve French 已提交
4919

4920 4921
	cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d  Offset %d\n",
		 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
L
Linus Torvalds 已提交
4922

4923
	/* parse returned result into more usable form */
4924 4925 4926 4927
	rc = parse_dfs_referrals(&pSMBr->dfs_data,
				 le16_to_cpu(pSMBr->t2.DataCount),
				 num_of_nodes, target_nodes, nls_codepage,
				 remap, search_name,
S
Steve French 已提交
4928
				 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
S
Steve French 已提交
4929

L
Linus Torvalds 已提交
4930
GetDFSRefExit:
4931
	cifs_buf_release(pSMB);
L
Linus Torvalds 已提交
4932 4933 4934 4935 4936 4937 4938

	if (rc == -EAGAIN)
		goto getDFSRetry;

	return rc;
}

4939 4940
/* Query File System Info such as free space to old servers such as Win 9x */
int
4941 4942
SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
	      struct kstatfs *FSData)
4943 4944 4945 4946 4947 4948 4949 4950 4951
{
/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
	TRANSACTION2_QFSI_REQ *pSMB = NULL;
	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
	FILE_SYSTEM_ALLOC_INFO *response_data;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count;

4952
	cifs_dbg(FYI, "OldQFSInfo\n");
4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978
oldQFSInfoRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		(void **) &pSMBr);
	if (rc)
		return rc;

	params = 2;     /* level */
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
	pSMB->MaxDataCount = cpu_to_le16(1000);
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
	struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4979
	inc_rfc1001_len(pSMB, byte_count);
4980 4981 4982 4983 4984
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
4985
		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
4986 4987 4988
	} else {                /* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

4989
		if (rc || get_bcc(&pSMBr->hdr) < 18)
4990 4991 4992
			rc = -EIO;      /* bad smb */
		else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4993
			cifs_dbg(FYI, "qfsinf resp BCC: %d  Offset %d\n",
4994
				 get_bcc(&pSMBr->hdr), data_offset);
4995

4996
			response_data = (FILE_SYSTEM_ALLOC_INFO *)
4997 4998 4999 5000 5001 5002
				(((char *) &pSMBr->hdr.Protocol) + data_offset);
			FSData->f_bsize =
				le16_to_cpu(response_data->BytesPerSector) *
				le32_to_cpu(response_data->
					SectorsPerAllocationUnit);
			FSData->f_blocks =
5003
			       le32_to_cpu(response_data->TotalAllocationUnits);
5004 5005
			FSData->f_bfree = FSData->f_bavail =
				le32_to_cpu(response_data->FreeAllocationUnits);
5006 5007 5008 5009
			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
				 (unsigned long long)FSData->f_blocks,
				 (unsigned long long)FSData->f_bfree,
				 FSData->f_bsize);
5010 5011 5012 5013 5014 5015 5016 5017 5018 5019
		}
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto oldQFSInfoRetry;

	return rc;
}

L
Linus Torvalds 已提交
5020
int
5021 5022
CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
	       struct kstatfs *FSData)
L
Linus Torvalds 已提交
5023 5024 5025 5026 5027 5028 5029 5030 5031
{
/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
	TRANSACTION2_QFSI_REQ *pSMB = NULL;
	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
	FILE_SYSTEM_INFO *response_data;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count;

5032
	cifs_dbg(FYI, "In QFSInfo\n");
L
Linus Torvalds 已提交
5033 5034 5035 5036 5037 5038 5039 5040 5041
QFSInfoRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	params = 2;	/* level */
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
5042
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
5043 5044 5045 5046 5047 5048 5049 5050 5051
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
5052
		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
5053 5054 5055 5056 5057 5058
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
5059
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5060 5061 5062 5063 5064
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
5065
		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
L
Linus Torvalds 已提交
5066
	} else {		/* decode response */
5067
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
L
Linus Torvalds 已提交
5068

5069
		if (rc || get_bcc(&pSMBr->hdr) < 24)
L
Linus Torvalds 已提交
5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085
			rc = -EIO;	/* bad smb */
		else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);

			response_data =
			    (FILE_SYSTEM_INFO
			     *) (((char *) &pSMBr->hdr.Protocol) +
				 data_offset);
			FSData->f_bsize =
			    le32_to_cpu(response_data->BytesPerSector) *
			    le32_to_cpu(response_data->
					SectorsPerAllocationUnit);
			FSData->f_blocks =
			    le64_to_cpu(response_data->TotalAllocationUnits);
			FSData->f_bfree = FSData->f_bavail =
			    le64_to_cpu(response_data->FreeAllocationUnits);
5086 5087 5088 5089
			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
				 (unsigned long long)FSData->f_blocks,
				 (unsigned long long)FSData->f_bfree,
				 FSData->f_bsize);
L
Linus Torvalds 已提交
5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100
		}
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto QFSInfoRetry;

	return rc;
}

int
5101
CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
L
Linus Torvalds 已提交
5102 5103 5104 5105 5106 5107 5108 5109 5110
{
/* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
	TRANSACTION2_QFSI_REQ *pSMB = NULL;
	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
	FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count;

5111
	cifs_dbg(FYI, "In QFSAttributeInfo\n");
L
Linus Torvalds 已提交
5112 5113 5114 5115 5116 5117 5118 5119 5120
QFSAttributeRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	params = 2;	/* level */
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
5121 5122
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
5123 5124 5125 5126 5127 5128 5129 5130 5131
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
5132
		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
5133 5134 5135 5136 5137 5138
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
5139
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5140 5141 5142 5143 5144
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
5145
		cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
L
Linus Torvalds 已提交
5146 5147 5148
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

5149
		if (rc || get_bcc(&pSMBr->hdr) < 13) {
5150
			/* BB also check if enough bytes returned */
L
Linus Torvalds 已提交
5151 5152 5153 5154 5155 5156 5157 5158
			rc = -EIO;	/* bad smb */
		} else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			response_data =
			    (FILE_SYSTEM_ATTRIBUTE_INFO
			     *) (((char *) &pSMBr->hdr.Protocol) +
				 data_offset);
			memcpy(&tcon->fsAttrInfo, response_data,
5159
			       sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
L
Linus Torvalds 已提交
5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170
		}
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto QFSAttributeRetry;

	return rc;
}

int
5171
CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
L
Linus Torvalds 已提交
5172 5173 5174 5175 5176 5177 5178 5179 5180
{
/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
	TRANSACTION2_QFSI_REQ *pSMB = NULL;
	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
	FILE_SYSTEM_DEVICE_INFO *response_data;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count;

5181
	cifs_dbg(FYI, "In QFSDeviceInfo\n");
L
Linus Torvalds 已提交
5182 5183 5184 5185 5186 5187 5188 5189 5190
QFSDeviceRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	params = 2;	/* level */
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
5191 5192
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
5193 5194 5195 5196 5197 5198 5199 5200 5201
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
5202
		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
5203 5204 5205 5206 5207 5208 5209

	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
5210
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5211 5212 5213 5214 5215
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
5216
		cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
L
Linus Torvalds 已提交
5217 5218 5219
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

5220 5221
		if (rc || get_bcc(&pSMBr->hdr) <
			  sizeof(FILE_SYSTEM_DEVICE_INFO))
L
Linus Torvalds 已提交
5222 5223 5224 5225
			rc = -EIO;	/* bad smb */
		else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			response_data =
5226 5227
			    (FILE_SYSTEM_DEVICE_INFO *)
				(((char *) &pSMBr->hdr.Protocol) +
L
Linus Torvalds 已提交
5228 5229
				 data_offset);
			memcpy(&tcon->fsDevInfo, response_data,
5230
			       sizeof(FILE_SYSTEM_DEVICE_INFO));
L
Linus Torvalds 已提交
5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241
		}
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto QFSDeviceRetry;

	return rc;
}

int
5242
CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
L
Linus Torvalds 已提交
5243 5244 5245 5246 5247 5248 5249 5250 5251
{
/* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
	TRANSACTION2_QFSI_REQ *pSMB = NULL;
	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
	FILE_SYSTEM_UNIX_INFO *response_data;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count;

5252
	cifs_dbg(FYI, "In QFSUnixInfo\n");
L
Linus Torvalds 已提交
5253
QFSUnixRetry:
5254 5255
	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
				   (void **) &pSMB, (void **) &pSMBr);
L
Linus Torvalds 已提交
5256 5257 5258 5259 5260 5261 5262 5263
	if (rc)
		return rc;

	params = 2;	/* level */
	pSMB->TotalDataCount = 0;
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
5264 5265
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(100);
L
Linus Torvalds 已提交
5266 5267 5268 5269 5270 5271 5272 5273
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
5274 5275
	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
5276 5277 5278 5279
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
5280
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5281 5282 5283 5284 5285
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
5286
		cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
L
Linus Torvalds 已提交
5287 5288 5289
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

5290
		if (rc || get_bcc(&pSMBr->hdr) < 13) {
L
Linus Torvalds 已提交
5291 5292 5293 5294 5295 5296 5297 5298
			rc = -EIO;	/* bad smb */
		} else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			response_data =
			    (FILE_SYSTEM_UNIX_INFO
			     *) (((char *) &pSMBr->hdr.Protocol) +
				 data_offset);
			memcpy(&tcon->fsUnixInfo, response_data,
5299
			       sizeof(FILE_SYSTEM_UNIX_INFO));
L
Linus Torvalds 已提交
5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310
		}
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto QFSUnixRetry;


	return rc;
}

5311
int
5312
CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
5313 5314 5315 5316 5317 5318 5319 5320
{
/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
	TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, param_offset, offset, byte_count;

5321
	cifs_dbg(FYI, "In SETFSUnixInfo\n");
5322
SETFSUnixRetry:
5323
	/* BB switch to small buf init to save memory */
5324 5325
	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
					(void **) &pSMB, (void **) &pSMBr);
5326 5327 5328 5329 5330 5331 5332 5333 5334
	if (rc)
		return rc;

	params = 4;	/* 2 bytes zero followed by info level. */
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
5335 5336
	param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
				- 4;
5337 5338 5339
	offset = param_offset + params;

	pSMB->MaxParameterCount = cpu_to_le16(4);
5340 5341
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(100);
5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
	byte_count = 1 /* pad */ + params + 12;

	pSMB->DataCount = cpu_to_le16(12);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);

	/* Params. */
	pSMB->FileNum = 0;
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);

	/* Data. */
	pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
	pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
	pSMB->ClientUnixCap = cpu_to_le64(cap);

5363
	inc_rfc1001_len(pSMB, byte_count);
5364 5365 5366 5367 5368
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
5369
		cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
5370 5371
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
S
Steve French 已提交
5372
		if (rc)
5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383
			rc = -EIO;	/* bad smb */
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto SETFSUnixRetry;

	return rc;
}


L
Linus Torvalds 已提交
5384 5385

int
5386
CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
5387
		   struct kstatfs *FSData)
L
Linus Torvalds 已提交
5388 5389 5390 5391 5392 5393 5394 5395 5396
{
/* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
	TRANSACTION2_QFSI_REQ *pSMB = NULL;
	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
	FILE_SYSTEM_POSIX_INFO *response_data;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, byte_count;

5397
	cifs_dbg(FYI, "In QFSPosixInfo\n");
L
Linus Torvalds 已提交
5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408
QFSPosixRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	params = 2;	/* level */
	pSMB->TotalDataCount = 0;
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
5409 5410
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(100);
L
Linus Torvalds 已提交
5411 5412 5413 5414 5415 5416 5417 5418
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	byte_count = params + 1 /* pad */ ;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
5419 5420
	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
5421 5422 5423 5424
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
5425
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5426 5427 5428 5429 5430
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
5431
		cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
L
Linus Torvalds 已提交
5432 5433 5434
	} else {		/* decode response */
		rc = validate_t2((struct smb_t2_rsp *)pSMBr);

5435
		if (rc || get_bcc(&pSMBr->hdr) < 13) {
L
Linus Torvalds 已提交
5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448
			rc = -EIO;	/* bad smb */
		} else {
			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
			response_data =
			    (FILE_SYSTEM_POSIX_INFO
			     *) (((char *) &pSMBr->hdr.Protocol) +
				 data_offset);
			FSData->f_bsize =
					le32_to_cpu(response_data->BlockSize);
			FSData->f_blocks =
					le64_to_cpu(response_data->TotalBlocks);
			FSData->f_bfree =
			    le64_to_cpu(response_data->BlocksAvail);
S
Steve French 已提交
5449
			if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
L
Linus Torvalds 已提交
5450 5451 5452
				FSData->f_bavail = FSData->f_bfree;
			} else {
				FSData->f_bavail =
5453
				    le64_to_cpu(response_data->UserBlocksAvail);
L
Linus Torvalds 已提交
5454
			}
S
Steve French 已提交
5455
			if (response_data->TotalFileNodes != cpu_to_le64(-1))
L
Linus Torvalds 已提交
5456
				FSData->f_files =
5457
				     le64_to_cpu(response_data->TotalFileNodes);
S
Steve French 已提交
5458
			if (response_data->FreeFileNodes != cpu_to_le64(-1))
L
Linus Torvalds 已提交
5459
				FSData->f_ffree =
5460
				      le64_to_cpu(response_data->FreeFileNodes);
L
Linus Torvalds 已提交
5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471
		}
	}
	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto QFSPosixRetry;

	return rc;
}


5472 5473 5474 5475 5476 5477
/*
 * We can not use write of zero bytes trick to set file size due to need for
 * large file support. Also note that this SetPathInfo is preferred to
 * SetFileInfo based method in next routine which is only needed to work around
 * a sharing violation bugin Samba which this routine can run into.
 */
L
Linus Torvalds 已提交
5478
int
5479
CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5480 5481
	      const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
	      bool set_allocation)
L
Linus Torvalds 已提交
5482 5483 5484 5485 5486 5487 5488
{
	struct smb_com_transaction2_spi_req *pSMB = NULL;
	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
	struct file_end_of_file_info *parm_data;
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
5489
	int remap = cifs_remap(cifs_sb);
5490

L
Linus Torvalds 已提交
5491 5492
	__u16 params, byte_count, data_count, param_offset, offset;

5493
	cifs_dbg(FYI, "In SetEOF\n");
L
Linus Torvalds 已提交
5494 5495 5496 5497 5498 5499 5500 5501
SetEOFRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
5502 5503
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
				       PATH_MAX, cifs_sb->local_nls, remap);
L
Linus Torvalds 已提交
5504 5505
		name_len++;	/* trailing null */
		name_len *= 2;
5506
	} else {	/* BB improve the check for buffer overruns BB */
5507
		name_len = strnlen(file_name, PATH_MAX);
L
Linus Torvalds 已提交
5508
		name_len++;	/* trailing null */
5509
		strncpy(pSMB->FileName, file_name, name_len);
L
Linus Torvalds 已提交
5510 5511
	}
	params = 6 + name_len;
5512
	data_count = sizeof(struct file_end_of_file_info);
L
Linus Torvalds 已提交
5513
	pSMB->MaxParameterCount = cpu_to_le16(2);
5514
	pSMB->MaxDataCount = cpu_to_le16(4100);
L
Linus Torvalds 已提交
5515 5516 5517 5518 5519 5520
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
5521
				InformationLevel) - 4;
L
Linus Torvalds 已提交
5522
	offset = param_offset + params;
5523
	if (set_allocation) {
5524 5525 5526 5527 5528 5529 5530
		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
			pSMB->InformationLevel =
				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
		else
			pSMB->InformationLevel =
				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
	} else /* Set File Size */  {
L
Linus Torvalds 已提交
5531 5532
	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
		    pSMB->InformationLevel =
5533
				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
L
Linus Torvalds 已提交
5534 5535
	    else
		    pSMB->InformationLevel =
5536
				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
L
Linus Torvalds 已提交
5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552
	}

	parm_data =
	    (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
				       offset);
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + data_count;
	pSMB->DataCount = cpu_to_le16(data_count);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->Reserved4 = 0;
5553
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5554 5555 5556 5557
	parm_data->FileSize = cpu_to_le64(size);
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
S
Steve French 已提交
5558
	if (rc)
5559
		cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
L
Linus Torvalds 已提交
5560 5561 5562 5563 5564 5565 5566 5567 5568 5569

	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto SetEOFRetry;

	return rc;
}

int
5570 5571
CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
		   struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
L
Linus Torvalds 已提交
5572 5573 5574 5575 5576 5577
{
	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
	struct file_end_of_file_info *parm_data;
	int rc = 0;
	__u16 params, param_offset, offset, byte_count, count;

5578 5579
	cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
		 (long long)size);
5580 5581
	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);

L
Linus Torvalds 已提交
5582 5583 5584
	if (rc)
		return rc;

5585 5586
	pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
5587

L
Linus Torvalds 已提交
5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598
	params = 6;
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
	offset = param_offset + params;

	count = sizeof(struct file_end_of_file_info);
	pSMB->MaxParameterCount = cpu_to_le16(2);
5599 5600
	/* BB find exact max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
5601 5602 5603 5604 5605 5606 5607 5608 5609 5610
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
	byte_count = 3 /* pad */  + params + count;
	pSMB->DataCount = cpu_to_le16(count);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	parm_data =
5611 5612
		(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
				+ offset);
L
Linus Torvalds 已提交
5613 5614
	pSMB->DataOffset = cpu_to_le16(offset);
	parm_data->FileSize = cpu_to_le64(size);
5615 5616
	pSMB->Fid = cfile->fid.netfid;
	if (set_allocation) {
L
Linus Torvalds 已提交
5617 5618 5619 5620 5621 5622
		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
			pSMB->InformationLevel =
				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
		else
			pSMB->InformationLevel =
				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5623
	} else /* Set File Size */  {
L
Linus Torvalds 已提交
5624 5625
	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
		    pSMB->InformationLevel =
5626
				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
L
Linus Torvalds 已提交
5627 5628
	    else
		    pSMB->InformationLevel =
5629
				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
L
Linus Torvalds 已提交
5630 5631
	}
	pSMB->Reserved4 = 0;
5632
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5633
	pSMB->ByteCount = cpu_to_le16(byte_count);
5634
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5635
	cifs_small_buf_release(pSMB);
L
Linus Torvalds 已提交
5636
	if (rc) {
5637 5638
		cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
			 rc);
L
Linus Torvalds 已提交
5639 5640
	}

5641
	/* Note: On -EAGAIN error only caller can retry on handle based calls
L
Linus Torvalds 已提交
5642 5643 5644 5645 5646
		since file handle passed in no longer valid */

	return rc;
}

5647
/* Some legacy servers such as NT4 require that the file times be set on
L
Linus Torvalds 已提交
5648 5649 5650 5651 5652 5653
   an open handle, rather than by pathname - this is awkward due to
   potential access conflicts on the open, but it is unavoidable for these
   old servers since the only other choice is to go from 100 nanosecond DCE
   time and resort to the original setpathinfo level which takes the ancient
   DOS time format with 2 second granularity */
int
5654
CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
5655
		    const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
L
Linus Torvalds 已提交
5656 5657 5658 5659 5660 5661
{
	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
	char *data_offset;
	int rc = 0;
	__u16 params, param_offset, offset, byte_count, count;

5662
	cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
5663 5664
	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);

L
Linus Torvalds 已提交
5665 5666 5667
	if (rc)
		return rc;

5668 5669
	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5670

L
Linus Torvalds 已提交
5671 5672 5673 5674 5675 5676 5677 5678 5679
	params = 6;
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
	offset = param_offset + params;

5680 5681
	data_offset = (char *)pSMB +
			offsetof(struct smb_hdr, Protocol) + offset;
L
Linus Torvalds 已提交
5682

5683
	count = sizeof(FILE_BASIC_INFO);
L
Linus Torvalds 已提交
5684
	pSMB->MaxParameterCount = cpu_to_le16(2);
5685 5686
	/* BB find max SMB PDU from sess */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
	byte_count = 3 /* pad */  + params + count;
	pSMB->DataCount = cpu_to_le16(count);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->Fid = fid;
	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
	else
		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
	pSMB->Reserved4 = 0;
5703
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
5704
	pSMB->ByteCount = cpu_to_le16(byte_count);
5705
	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
5706
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5707
	cifs_small_buf_release(pSMB);
S
Steve French 已提交
5708
	if (rc)
5709 5710
		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
			 rc);
L
Linus Torvalds 已提交
5711

5712
	/* Note: On -EAGAIN error only caller can retry on handle based calls
L
Linus Torvalds 已提交
5713 5714 5715 5716 5717
		since file handle passed in no longer valid */

	return rc;
}

5718
int
5719
CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
5720 5721 5722 5723 5724 5725 5726
			  bool delete_file, __u16 fid, __u32 pid_of_opener)
{
	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
	char *data_offset;
	int rc = 0;
	__u16 params, param_offset, offset, byte_count, count;

5727
	cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763
	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);

	if (rc)
		return rc;

	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));

	params = 6;
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
	offset = param_offset + params;

	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;

	count = 1;
	pSMB->MaxParameterCount = cpu_to_le16(2);
	/* BB find max SMB PDU from sess */
	pSMB->MaxDataCount = cpu_to_le16(1000);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
	byte_count = 3 /* pad */  + params + count;
	pSMB->DataCount = cpu_to_le16(count);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->Fid = fid;
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
	pSMB->Reserved4 = 0;
5764
	inc_rfc1001_len(pSMB, byte_count);
5765 5766
	pSMB->ByteCount = cpu_to_le16(byte_count);
	*data_offset = delete_file ? 1 : 0;
5767
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
5768
	cifs_small_buf_release(pSMB);
5769
	if (rc)
5770
		cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
5771 5772 5773

	return rc;
}
L
Linus Torvalds 已提交
5774 5775

int
5776
CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
5777 5778
		   const char *fileName, const FILE_BASIC_INFO *data,
		   const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
5779 5780 5781 5782 5783 5784 5785 5786 5787
{
	TRANSACTION2_SPI_REQ *pSMB = NULL;
	TRANSACTION2_SPI_RSP *pSMBr = NULL;
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
	char *data_offset;
	__u16 params, param_offset, offset, byte_count, count;

5788
	cifs_dbg(FYI, "In SetTimes\n");
L
Linus Torvalds 已提交
5789 5790 5791 5792 5793 5794 5795 5796 5797

SetTimesRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
5798 5799
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
				       PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
5800 5801
		name_len++;	/* trailing null */
		name_len *= 2;
5802
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
5803 5804 5805 5806 5807 5808
		name_len = strnlen(fileName, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, fileName, name_len);
	}

	params = 6 + name_len;
5809
	count = sizeof(FILE_BASIC_INFO);
L
Linus Torvalds 已提交
5810
	pSMB->MaxParameterCount = cpu_to_le16(2);
5811 5812
	/* BB find max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
5813 5814 5815 5816 5817 5818
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
5819
				InformationLevel) - 4;
L
Linus Torvalds 已提交
5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837
	offset = param_offset + params;
	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + count;

	pSMB->DataCount = cpu_to_le16(count);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
	else
		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
	pSMB->Reserved4 = 0;
5838
	inc_rfc1001_len(pSMB, byte_count);
5839
	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
L
Linus Torvalds 已提交
5840 5841 5842
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
S
Steve French 已提交
5843
	if (rc)
5844
		cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
L
Linus Torvalds 已提交
5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859

	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto SetTimesRetry;

	return rc;
}

/* Can not be used to set time stamps yet (due to old DOS time format) */
/* Can be used to set attributes */
#if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
	  handling it anyway and NT4 was what we thought it would be needed for
	  Do not delete it until we prove whether needed for Win9x though */
int
5860
CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
L
Linus Torvalds 已提交
5861 5862 5863 5864 5865 5866 5867 5868
		__u16 dos_attrs, const struct nls_table *nls_codepage)
{
	SETATTR_REQ *pSMB = NULL;
	SETATTR_RSP *pSMBr = NULL;
	int rc = 0;
	int bytes_returned;
	int name_len;

5869
	cifs_dbg(FYI, "In SetAttrLegacy\n");
L
Linus Torvalds 已提交
5870 5871 5872 5873 5874 5875 5876 5877 5878

SetAttrLgcyRetry:
	rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
5879 5880
			ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
				       PATH_MAX, nls_codepage);
L
Linus Torvalds 已提交
5881 5882
		name_len++;     /* trailing null */
		name_len *= 2;
5883
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
5884 5885 5886 5887 5888 5889
		name_len = strnlen(fileName, PATH_MAX);
		name_len++;     /* trailing null */
		strncpy(pSMB->fileName, fileName, name_len);
	}
	pSMB->attr = cpu_to_le16(dos_attrs);
	pSMB->BufferFormat = 0x04;
5890
	inc_rfc1001_len(pSMB, name_len + 1);
L
Linus Torvalds 已提交
5891 5892 5893
	pSMB->ByteCount = cpu_to_le16(name_len + 1);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
S
Steve French 已提交
5894
	if (rc)
5895
		cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
L
Linus Torvalds 已提交
5896 5897 5898 5899 5900 5901 5902 5903 5904 5905

	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto SetAttrLgcyRetry;

	return rc;
}
#endif /* temporarily unneeded SetAttr legacy function */

5906 5907 5908 5909
static void
cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
			const struct cifs_unix_set_info_args *args)
{
5910
	u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
5911 5912
	u64 mode = args->mode;

5913 5914 5915 5916 5917
	if (uid_valid(args->uid))
		uid = from_kuid(&init_user_ns, args->uid);
	if (gid_valid(args->gid))
		gid = from_kgid(&init_user_ns, args->gid);

5918 5919 5920 5921
	/*
	 * Samba server ignores set of file size to zero due to bugs in some
	 * older clients, but we should be precise - we use SetFileSize to
	 * set file size and do not want to truncate file size to zero
L
Lucas De Marchi 已提交
5922
	 * accidentally as happened on one Samba server beta by putting
5923 5924 5925 5926 5927 5928 5929
	 * zero instead of -1 here
	 */
	data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
	data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
	data_offset->LastStatusChange = cpu_to_le64(args->ctime);
	data_offset->LastAccessTime = cpu_to_le64(args->atime);
	data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5930 5931
	data_offset->Uid = cpu_to_le64(uid);
	data_offset->Gid = cpu_to_le64(gid);
5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952
	/* better to leave device as zero when it is  */
	data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
	data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
	data_offset->Permissions = cpu_to_le64(mode);

	if (S_ISREG(mode))
		data_offset->Type = cpu_to_le32(UNIX_FILE);
	else if (S_ISDIR(mode))
		data_offset->Type = cpu_to_le32(UNIX_DIR);
	else if (S_ISLNK(mode))
		data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
	else if (S_ISCHR(mode))
		data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
	else if (S_ISBLK(mode))
		data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
	else if (S_ISFIFO(mode))
		data_offset->Type = cpu_to_le32(UNIX_FIFO);
	else if (S_ISSOCK(mode))
		data_offset->Type = cpu_to_le32(UNIX_SOCKET);
}

5953
int
5954
CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
5955 5956 5957 5958
		       const struct cifs_unix_set_info_args *args,
		       u16 fid, u32 pid_of_opener)
{
	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
5959
	char *data_offset;
5960 5961 5962
	int rc = 0;
	u16 params, param_offset, offset, byte_count, count;

5963
	cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980
	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);

	if (rc)
		return rc;

	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));

	params = 6;
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
	offset = param_offset + params;

5981 5982 5983
	data_offset = (char *)pSMB +
			offsetof(struct smb_hdr, Protocol) + offset;

5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001
	count = sizeof(FILE_UNIX_BASIC_INFO);

	pSMB->MaxParameterCount = cpu_to_le16(2);
	/* BB find max SMB PDU from sess */
	pSMB->MaxDataCount = cpu_to_le16(1000);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
	byte_count = 3 /* pad */  + params + count;
	pSMB->DataCount = cpu_to_le16(count);
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->Fid = fid;
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
	pSMB->Reserved4 = 0;
6002
	inc_rfc1001_len(pSMB, byte_count);
6003 6004
	pSMB->ByteCount = cpu_to_le16(byte_count);

6005
	cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
6006

6007
	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
6008
	cifs_small_buf_release(pSMB);
6009
	if (rc)
6010 6011
		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
			 rc);
6012 6013 6014 6015 6016 6017 6018

	/* Note: On -EAGAIN error only caller can retry on handle based calls
		since file handle passed in no longer valid */

	return rc;
}

L
Linus Torvalds 已提交
6019
int
6020
CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
P
Pavel Shilovsky 已提交
6021
		       const char *file_name,
6022 6023
		       const struct cifs_unix_set_info_args *args,
		       const struct nls_table *nls_codepage, int remap)
L
Linus Torvalds 已提交
6024 6025 6026 6027 6028 6029 6030 6031 6032
{
	TRANSACTION2_SPI_REQ *pSMB = NULL;
	TRANSACTION2_SPI_RSP *pSMBr = NULL;
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
	FILE_UNIX_BASIC_INFO *data_offset;
	__u16 params, param_offset, offset, count, byte_count;

6033
	cifs_dbg(FYI, "In SetUID/GID/Mode\n");
L
Linus Torvalds 已提交
6034 6035 6036 6037 6038 6039 6040 6041
setPermsRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
P
Pavel Shilovsky 已提交
6042
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
6043
				       PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
6044 6045
		name_len++;	/* trailing null */
		name_len *= 2;
6046
	} else {	/* BB improve the check for buffer overruns BB */
P
Pavel Shilovsky 已提交
6047
		name_len = strnlen(file_name, PATH_MAX);
L
Linus Torvalds 已提交
6048
		name_len++;	/* trailing null */
P
Pavel Shilovsky 已提交
6049
		strncpy(pSMB->FileName, file_name, name_len);
L
Linus Torvalds 已提交
6050 6051 6052
	}

	params = 6 + name_len;
6053
	count = sizeof(FILE_UNIX_BASIC_INFO);
L
Linus Torvalds 已提交
6054
	pSMB->MaxParameterCount = cpu_to_le16(2);
6055 6056
	/* BB find max SMB PDU from sess structure BB */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
6057 6058 6059 6060 6061 6062
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
6063
				InformationLevel) - 4;
L
Linus Torvalds 已提交
6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080
	offset = param_offset + params;
	data_offset =
	    (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
				      offset);
	memset(data_offset, 0, count);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + count;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->DataCount = cpu_to_le16(count);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
	pSMB->Reserved4 = 0;
6081
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
6082

6083
	cifs_fill_unix_set_info(data_offset, args);
L
Linus Torvalds 已提交
6084 6085 6086 6087

	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
S
Steve French 已提交
6088
	if (rc)
6089
		cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
L
Linus Torvalds 已提交
6090

6091
	cifs_buf_release(pSMB);
L
Linus Torvalds 已提交
6092 6093 6094 6095 6096 6097
	if (rc == -EAGAIN)
		goto setPermsRetry;
	return rc;
}

#ifdef CONFIG_CIFS_XATTR
6098 6099 6100 6101 6102 6103 6104 6105 6106
/*
 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
 * function used by listxattr and getxattr type calls. When ea_name is set,
 * it looks for that attribute name and stuffs that value into the EAData
 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
 * buffer. In both cases, the return value is either the length of the
 * resulting data or a negative error code. If EAData is a NULL pointer then
 * the data isn't copied to it, but the length is returned.
 */
L
Linus Torvalds 已提交
6107
ssize_t
6108
CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
6109 6110
		const unsigned char *searchName, const unsigned char *ea_name,
		char *EAData, size_t buf_size,
6111
		struct cifs_sb_info *cifs_sb)
L
Linus Torvalds 已提交
6112 6113 6114 6115
{
		/* BB assumes one setup word */
	TRANSACTION2_QPI_REQ *pSMB = NULL;
	TRANSACTION2_QPI_RSP *pSMBr = NULL;
6116 6117
	int remap = cifs_remap(cifs_sb);
	struct nls_table *nls_codepage = cifs_sb->local_nls;
L
Linus Torvalds 已提交
6118 6119
	int rc = 0;
	int bytes_returned;
6120
	int list_len;
6121
	struct fealist *ea_response_data;
6122 6123
	struct fea *temp_fea;
	char *temp_ptr;
6124
	char *end_of_smb;
6125
	__u16 params, byte_count, data_offset;
6126
	unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
L
Linus Torvalds 已提交
6127

6128
	cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
L
Linus Torvalds 已提交
6129 6130 6131 6132 6133 6134 6135
QAllEAsRetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6136
		list_len =
6137 6138
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
				       PATH_MAX, nls_codepage, remap);
6139 6140
		list_len++;	/* trailing null */
		list_len *= 2;
L
Linus Torvalds 已提交
6141
	} else {	/* BB improve the check for buffer overruns BB */
6142 6143 6144
		list_len = strnlen(searchName, PATH_MAX);
		list_len++;	/* trailing null */
		strncpy(pSMB->FileName, searchName, list_len);
L
Linus Torvalds 已提交
6145 6146
	}

6147
	params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
L
Linus Torvalds 已提交
6148 6149
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le16(2);
6150
	/* BB find exact max SMB PDU from sess structure BB */
6151
	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
L
Linus Torvalds 已提交
6152 6153 6154 6155 6156 6157
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	pSMB->ParameterOffset = cpu_to_le16(offsetof(
6158
	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
L
Linus Torvalds 已提交
6159 6160 6161 6162 6163 6164 6165 6166 6167 6168
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
	byte_count = params + 1 /* pad */ ;
	pSMB->TotalParameterCount = cpu_to_le16(params);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
	pSMB->Reserved4 = 0;
6169
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
6170 6171 6172 6173 6174
	pSMB->ByteCount = cpu_to_le16(byte_count);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc) {
6175
		cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
6176 6177
		goto QAllEAsOut;
	}
L
Linus Torvalds 已提交
6178

6179 6180 6181 6182 6183 6184

	/* BB also check enough total bytes returned */
	/* BB we need to improve the validity checking
	of these trans2 responses */

	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6185
	if (rc || get_bcc(&pSMBr->hdr) < 4) {
6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201
		rc = -EIO;	/* bad smb */
		goto QAllEAsOut;
	}

	/* check that length of list is not more than bcc */
	/* check that each entry does not go beyond length
	   of list */
	/* check that each element of each entry does not
	   go beyond end of list */
	/* validate_trans2_offsets() */
	/* BB check if start of smb + data_offset > &bcc+ bcc */

	data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
	ea_response_data = (struct fealist *)
				(((char *) &pSMBr->hdr.Protocol) + data_offset);

6202
	list_len = le32_to_cpu(ea_response_data->list_len);
6203
	cifs_dbg(FYI, "ea length %d\n", list_len);
6204
	if (list_len <= 8) {
6205
		cifs_dbg(FYI, "empty EA list returned from server\n");
6206 6207 6208
		/* didn't find the named attribute */
		if (ea_name)
			rc = -ENODATA;
6209 6210 6211
		goto QAllEAsOut;
	}

6212
	/* make sure list_len doesn't go past end of SMB */
6213
	end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
6214
	if ((char *)ea_response_data + list_len > end_of_smb) {
6215
		cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
6216 6217 6218 6219
		rc = -EIO;
		goto QAllEAsOut;
	}

6220
	/* account for ea list len */
6221
	list_len -= 4;
6222 6223
	temp_fea = ea_response_data->list;
	temp_ptr = (char *)temp_fea;
6224
	while (list_len > 0) {
6225
		unsigned int name_len;
6226
		__u16 value_len;
6227

6228
		list_len -= 4;
6229
		temp_ptr += 4;
6230 6231
		/* make sure we can read name_len and value_len */
		if (list_len < 0) {
6232
			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6233 6234 6235 6236 6237 6238 6239 6240
			rc = -EIO;
			goto QAllEAsOut;
		}

		name_len = temp_fea->name_len;
		value_len = le16_to_cpu(temp_fea->value_len);
		list_len -= name_len + 1 + value_len;
		if (list_len < 0) {
6241
			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
6242 6243 6244 6245
			rc = -EIO;
			goto QAllEAsOut;
		}

6246
		if (ea_name) {
6247
			if (ea_name_len == name_len &&
6248
			    memcmp(ea_name, temp_ptr, name_len) == 0) {
6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259
				temp_ptr += name_len + 1;
				rc = value_len;
				if (buf_size == 0)
					goto QAllEAsOut;
				if ((size_t)value_len > buf_size) {
					rc = -ERANGE;
					goto QAllEAsOut;
				}
				memcpy(EAData, temp_ptr, value_len);
				goto QAllEAsOut;
			}
6260
		} else {
6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277
			/* account for prefix user. and trailing null */
			rc += (5 + 1 + name_len);
			if (rc < (int) buf_size) {
				memcpy(EAData, "user.", 5);
				EAData += 5;
				memcpy(EAData, temp_ptr, name_len);
				EAData += name_len;
				/* null terminate name */
				*EAData = 0;
				++EAData;
			} else if (buf_size == 0) {
				/* skip copy - calc size only */
			} else {
				/* stop before overrun buffer */
				rc = -ERANGE;
				break;
			}
L
Linus Torvalds 已提交
6278
		}
6279
		temp_ptr += name_len + 1 + value_len;
6280
		temp_fea = (struct fea *)temp_ptr;
L
Linus Torvalds 已提交
6281
	}
6282

6283 6284 6285 6286
	/* didn't find the named attribute */
	if (ea_name)
		rc = -ENODATA;

6287
QAllEAsOut:
6288
	cifs_buf_release(pSMB);
L
Linus Torvalds 已提交
6289 6290 6291 6292 6293 6294 6295
	if (rc == -EAGAIN)
		goto QAllEAsRetry;

	return (ssize_t)rc;
}

int
6296 6297
CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
	     const char *fileName, const char *ea_name, const void *ea_value,
6298
	     const __u16 ea_value_len, const struct nls_table *nls_codepage,
6299
	     struct cifs_sb_info *cifs_sb)
L
Linus Torvalds 已提交
6300 6301 6302 6303 6304 6305 6306 6307
{
	struct smb_com_transaction2_spi_req *pSMB = NULL;
	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
	struct fealist *parm_data;
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
	__u16 params, param_offset, byte_count, offset, count;
6308
	int remap = cifs_remap(cifs_sb);
L
Linus Torvalds 已提交
6309

6310
	cifs_dbg(FYI, "In SetEA\n");
L
Linus Torvalds 已提交
6311 6312 6313 6314 6315 6316 6317 6318
SetEARetry:
	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
6319 6320
		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
				       PATH_MAX, nls_codepage, remap);
L
Linus Torvalds 已提交
6321 6322
		name_len++;	/* trailing null */
		name_len *= 2;
6323
	} else {	/* BB improve the check for buffer overruns BB */
L
Linus Torvalds 已提交
6324 6325 6326 6327 6328 6329 6330 6331 6332 6333
		name_len = strnlen(fileName, PATH_MAX);
		name_len++;	/* trailing null */
		strncpy(pSMB->FileName, fileName, name_len);
	}

	params = 6 + name_len;

	/* done calculating parms using name_len of file name,
	now use name_len to calculate length of ea name
	we are going to create in the inode xattrs */
S
Steve French 已提交
6334
	if (ea_name == NULL)
L
Linus Torvalds 已提交
6335 6336
		name_len = 0;
	else
6337
		name_len = strnlen(ea_name, 255);
L
Linus Torvalds 已提交
6338

6339
	count = sizeof(*parm_data) + ea_value_len + name_len;
L
Linus Torvalds 已提交
6340
	pSMB->MaxParameterCount = cpu_to_le16(2);
6341 6342
	/* BB find max SMB PDU from sess */
	pSMB->MaxDataCount = cpu_to_le16(1000);
L
Linus Torvalds 已提交
6343 6344 6345 6346 6347 6348
	pSMB->MaxSetupCount = 0;
	pSMB->Reserved = 0;
	pSMB->Flags = 0;
	pSMB->Timeout = 0;
	pSMB->Reserved2 = 0;
	param_offset = offsetof(struct smb_com_transaction2_spi_req,
6349
				InformationLevel) - 4;
L
Linus Torvalds 已提交
6350 6351 6352 6353
	offset = param_offset + params;
	pSMB->InformationLevel =
		cpu_to_le16(SMB_SET_FILE_EA);

6354
	parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
L
Linus Torvalds 已提交
6355 6356 6357 6358 6359 6360 6361 6362 6363 6364
	pSMB->ParameterOffset = cpu_to_le16(param_offset);
	pSMB->DataOffset = cpu_to_le16(offset);
	pSMB->SetupCount = 1;
	pSMB->Reserved3 = 0;
	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
	byte_count = 3 /* pad */  + params + count;
	pSMB->DataCount = cpu_to_le16(count);
	parm_data->list_len = cpu_to_le32(count);
	parm_data->list[0].EA_flags = 0;
	/* we checked above that name len is less than 255 */
A
Alexey Dobriyan 已提交
6365
	parm_data->list[0].name_len = (__u8)name_len;
L
Linus Torvalds 已提交
6366
	/* EA names are always ASCII */
S
Steve French 已提交
6367
	if (ea_name)
6368
		strncpy(parm_data->list[0].name, ea_name, name_len);
L
Linus Torvalds 已提交
6369 6370 6371 6372 6373
	parm_data->list[0].name[name_len] = 0;
	parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
	/* caller ensures that ea_value_len is less than 64K but
	we need to ensure that it fits within the smb */

6374 6375
	/*BB add length check to see if it would fit in
	     negotiated SMB buffer size BB */
S
Steve French 已提交
6376 6377
	/* if (ea_value_len > buffer_size - 512 (enough for header)) */
	if (ea_value_len)
6378 6379
		memcpy(parm_data->list[0].name+name_len+1,
		       ea_value, ea_value_len);
L
Linus Torvalds 已提交
6380 6381 6382 6383 6384

	pSMB->TotalDataCount = pSMB->DataCount;
	pSMB->ParameterCount = cpu_to_le16(params);
	pSMB->TotalParameterCount = pSMB->ParameterCount;
	pSMB->Reserved4 = 0;
6385
	inc_rfc1001_len(pSMB, byte_count);
L
Linus Torvalds 已提交
6386 6387 6388
	pSMB->ByteCount = cpu_to_le16(byte_count);
	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
S
Steve French 已提交
6389
	if (rc)
6390
		cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
L
Linus Torvalds 已提交
6391 6392 6393 6394 6395 6396 6397 6398 6399

	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto SetEARetry;

	return rc;
}
#endif
6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421

#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
/*
 *	Years ago the kernel added a "dnotify" function for Samba server,
 *	to allow network clients (such as Windows) to display updated
 *	lists of files in directory listings automatically when
 *	files are added by one user when another user has the
 *	same directory open on their desktop.  The Linux cifs kernel
 *	client hooked into the kernel side of this interface for
 *	the same reason, but ironically when the VFS moved from
 *	"dnotify" to "inotify" it became harder to plug in Linux
 *	network file system clients (the most obvious use case
 *	for notify interfaces is when multiple users can update
 *	the contents of the same directory - exactly what network
 *	file systems can do) although the server (Samba) could
 *	still use it.  For the short term we leave the worker
 *	function ifdeffed out (below) until inotify is fixed
 *	in the VFS to make it easier to plug in network file
 *	system clients.  If inotify turns out to be permanently
 *	incompatible for network fs clients, we could instead simply
 *	expose this config flag by adding a future cifs (and smb2) notify ioctl.
 */
6422
int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
6423 6424 6425 6426 6427 6428 6429 6430 6431 6432
		  const int notify_subdirs, const __u16 netfid,
		  __u32 filter, struct file *pfile, int multishot,
		  const struct nls_table *nls_codepage)
{
	int rc = 0;
	struct smb_com_transaction_change_notify_req *pSMB = NULL;
	struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
	struct dir_notify_req *dnotify_req;
	int bytes_returned;

6433
	cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
6434 6435 6436 6437 6438 6439 6440 6441
	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	pSMB->TotalParameterCount = 0 ;
	pSMB->TotalDataCount = 0;
	pSMB->MaxParameterCount = cpu_to_le32(2);
6442
	pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461
	pSMB->MaxSetupCount = 4;
	pSMB->Reserved = 0;
	pSMB->ParameterOffset = 0;
	pSMB->DataCount = 0;
	pSMB->DataOffset = 0;
	pSMB->SetupCount = 4; /* single byte does not need le conversion */
	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
	pSMB->ParameterCount = pSMB->TotalParameterCount;
	if (notify_subdirs)
		pSMB->WatchTree = 1; /* one byte - no le conversion needed */
	pSMB->Reserved2 = 0;
	pSMB->CompletionFilter = cpu_to_le32(filter);
	pSMB->Fid = netfid; /* file handle always le */
	pSMB->ByteCount = 0;

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *)pSMBr, &bytes_returned,
			 CIFS_ASYNC_OP);
	if (rc) {
6462
		cifs_dbg(FYI, "Error in Notify = %d\n", rc);
6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489
	} else {
		/* Add file to outstanding requests */
		/* BB change to kmem cache alloc */
		dnotify_req = kmalloc(
						sizeof(struct dir_notify_req),
						 GFP_KERNEL);
		if (dnotify_req) {
			dnotify_req->Pid = pSMB->hdr.Pid;
			dnotify_req->PidHigh = pSMB->hdr.PidHigh;
			dnotify_req->Mid = pSMB->hdr.Mid;
			dnotify_req->Tid = pSMB->hdr.Tid;
			dnotify_req->Uid = pSMB->hdr.Uid;
			dnotify_req->netfid = netfid;
			dnotify_req->pfile = pfile;
			dnotify_req->filter = filter;
			dnotify_req->multishot = multishot;
			spin_lock(&GlobalMid_Lock);
			list_add_tail(&dnotify_req->lhead,
					&GlobalDnotifyReqList);
			spin_unlock(&GlobalMid_Lock);
		} else
			rc = -ENOMEM;
	}
	cifs_buf_release(pSMB);
	return rc;
}
#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */