xref: /openbmc/linux/fs/smb/client/cifssmb.c (revision f93d145f)
138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *
438c8a9a5SSteve French  *   Copyright (C) International Business Machines  Corp., 2002,2010
538c8a9a5SSteve French  *   Author(s): Steve French (sfrench@us.ibm.com)
638c8a9a5SSteve French  *
738c8a9a5SSteve French  *   Contains the routines for constructing the SMB PDUs themselves
838c8a9a5SSteve French  *
938c8a9a5SSteve French  */
1038c8a9a5SSteve French 
1138c8a9a5SSteve French  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
1238c8a9a5SSteve French  /* These are mostly routines that operate on a pathname, or on a tree id     */
1338c8a9a5SSteve French  /* (mounted volume), but there are eight handle based routines which must be */
1438c8a9a5SSteve French  /* treated slightly differently for reconnection purposes since we never     */
1538c8a9a5SSteve French  /* want to reuse a stale file handle and only the caller knows the file info */
1638c8a9a5SSteve French 
1738c8a9a5SSteve French #include <linux/fs.h>
1838c8a9a5SSteve French #include <linux/filelock.h>
1938c8a9a5SSteve French #include <linux/kernel.h>
2038c8a9a5SSteve French #include <linux/vfs.h>
2138c8a9a5SSteve French #include <linux/slab.h>
2238c8a9a5SSteve French #include <linux/posix_acl_xattr.h>
2338c8a9a5SSteve French #include <linux/pagemap.h>
2438c8a9a5SSteve French #include <linux/swap.h>
2538c8a9a5SSteve French #include <linux/task_io_accounting_ops.h>
2638c8a9a5SSteve French #include <linux/uaccess.h>
2738c8a9a5SSteve French #include "cifspdu.h"
2838c8a9a5SSteve French #include "cifsfs.h"
2938c8a9a5SSteve French #include "cifsglob.h"
3038c8a9a5SSteve French #include "cifsacl.h"
3138c8a9a5SSteve French #include "cifsproto.h"
3238c8a9a5SSteve French #include "cifs_unicode.h"
3338c8a9a5SSteve French #include "cifs_debug.h"
3438c8a9a5SSteve French #include "fscache.h"
3538c8a9a5SSteve French #include "smbdirect.h"
3638c8a9a5SSteve French #ifdef CONFIG_CIFS_DFS_UPCALL
3738c8a9a5SSteve French #include "dfs_cache.h"
3838c8a9a5SSteve French #endif
3938c8a9a5SSteve French 
4038c8a9a5SSteve French #ifdef CONFIG_CIFS_POSIX
4138c8a9a5SSteve French static struct {
4238c8a9a5SSteve French 	int index;
4338c8a9a5SSteve French 	char *name;
4438c8a9a5SSteve French } protocols[] = {
4538c8a9a5SSteve French 	{CIFS_PROT, "\2NT LM 0.12"},
4638c8a9a5SSteve French 	{POSIX_PROT, "\2POSIX 2"},
4738c8a9a5SSteve French 	{BAD_PROT, "\2"}
4838c8a9a5SSteve French };
4938c8a9a5SSteve French #else
5038c8a9a5SSteve French static struct {
5138c8a9a5SSteve French 	int index;
5238c8a9a5SSteve French 	char *name;
5338c8a9a5SSteve French } protocols[] = {
5438c8a9a5SSteve French 	{CIFS_PROT, "\2NT LM 0.12"},
5538c8a9a5SSteve French 	{BAD_PROT, "\2"}
5638c8a9a5SSteve French };
5738c8a9a5SSteve French #endif
5838c8a9a5SSteve French 
5938c8a9a5SSteve French /* define the number of elements in the cifs dialect array */
6038c8a9a5SSteve French #ifdef CONFIG_CIFS_POSIX
6138c8a9a5SSteve French #define CIFS_NUM_PROT 2
6238c8a9a5SSteve French #else /* not posix */
6338c8a9a5SSteve French #define CIFS_NUM_PROT 1
6438c8a9a5SSteve French #endif /* CIFS_POSIX */
6538c8a9a5SSteve French 
6638c8a9a5SSteve French 
6738c8a9a5SSteve French /* reconnect the socket, tcon, and smb session if needed */
6838c8a9a5SSteve French static int
cifs_reconnect_tcon(struct cifs_tcon * tcon,int smb_command)6938c8a9a5SSteve French cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
7038c8a9a5SSteve French {
7138c8a9a5SSteve French 	int rc;
7238c8a9a5SSteve French 	struct cifs_ses *ses;
7338c8a9a5SSteve French 	struct TCP_Server_Info *server;
7438c8a9a5SSteve French 	struct nls_table *nls_codepage = NULL;
7538c8a9a5SSteve French 
7638c8a9a5SSteve French 	/*
7738c8a9a5SSteve French 	 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
7838c8a9a5SSteve French 	 * tcp and smb session status done differently for those three - in the
7938c8a9a5SSteve French 	 * calling routine
8038c8a9a5SSteve French 	 */
8138c8a9a5SSteve French 	if (!tcon)
8238c8a9a5SSteve French 		return 0;
8338c8a9a5SSteve French 
8438c8a9a5SSteve French 	ses = tcon->ses;
8538c8a9a5SSteve French 	server = ses->server;
8638c8a9a5SSteve French 
8738c8a9a5SSteve French 	/*
8838c8a9a5SSteve French 	 * only tree disconnect, open, and write, (and ulogoff which does not
8938c8a9a5SSteve French 	 * have tcon) are allowed as we start umount
9038c8a9a5SSteve French 	 */
9138c8a9a5SSteve French 	spin_lock(&tcon->tc_lock);
9238c8a9a5SSteve French 	if (tcon->status == TID_EXITING) {
9338c8a9a5SSteve French 		if (smb_command != SMB_COM_TREE_DISCONNECT) {
9438c8a9a5SSteve French 			spin_unlock(&tcon->tc_lock);
9538c8a9a5SSteve French 			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
9638c8a9a5SSteve French 				 smb_command);
9738c8a9a5SSteve French 			return -ENODEV;
9838c8a9a5SSteve French 		}
9938c8a9a5SSteve French 	}
10038c8a9a5SSteve French 	spin_unlock(&tcon->tc_lock);
10138c8a9a5SSteve French 
10238c8a9a5SSteve French again:
10338c8a9a5SSteve French 	rc = cifs_wait_for_server_reconnect(server, tcon->retry);
10438c8a9a5SSteve French 	if (rc)
10538c8a9a5SSteve French 		return rc;
10638c8a9a5SSteve French 
10738c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
10838c8a9a5SSteve French 	if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
10938c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
11038c8a9a5SSteve French 		return 0;
11138c8a9a5SSteve French 	}
11238c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
11338c8a9a5SSteve French 
11438c8a9a5SSteve French 	mutex_lock(&ses->session_mutex);
11538c8a9a5SSteve French 	/*
11638c8a9a5SSteve French 	 * Recheck after acquire mutex. If another thread is negotiating
11738c8a9a5SSteve French 	 * and the server never sends an answer the socket will be closed
11838c8a9a5SSteve French 	 * and tcpStatus set to reconnect.
11938c8a9a5SSteve French 	 */
12038c8a9a5SSteve French 	spin_lock(&server->srv_lock);
12138c8a9a5SSteve French 	if (server->tcpStatus == CifsNeedReconnect) {
12238c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
12338c8a9a5SSteve French 		mutex_unlock(&ses->session_mutex);
12438c8a9a5SSteve French 
12538c8a9a5SSteve French 		if (tcon->retry)
12638c8a9a5SSteve French 			goto again;
12738c8a9a5SSteve French 		rc = -EHOSTDOWN;
12838c8a9a5SSteve French 		goto out;
12938c8a9a5SSteve French 	}
13038c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
13138c8a9a5SSteve French 
132a43f95fdSWinston Wen 	nls_codepage = ses->local_nls;
13338c8a9a5SSteve French 
13438c8a9a5SSteve French 	/*
13538c8a9a5SSteve French 	 * need to prevent multiple threads trying to simultaneously
13638c8a9a5SSteve French 	 * reconnect the same SMB session
13738c8a9a5SSteve French 	 */
13838c8a9a5SSteve French 	spin_lock(&ses->ses_lock);
13938c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
14038c8a9a5SSteve French 	if (!cifs_chan_needs_reconnect(ses, server) &&
14138c8a9a5SSteve French 	    ses->ses_status == SES_GOOD) {
14238c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
14338c8a9a5SSteve French 		spin_unlock(&ses->ses_lock);
14438c8a9a5SSteve French 
14538c8a9a5SSteve French 		/* this means that we only need to tree connect */
14638c8a9a5SSteve French 		if (tcon->need_reconnect)
14738c8a9a5SSteve French 			goto skip_sess_setup;
14838c8a9a5SSteve French 
14938c8a9a5SSteve French 		mutex_unlock(&ses->session_mutex);
15038c8a9a5SSteve French 		goto out;
15138c8a9a5SSteve French 	}
15238c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
15338c8a9a5SSteve French 	spin_unlock(&ses->ses_lock);
15438c8a9a5SSteve French 
15538c8a9a5SSteve French 	rc = cifs_negotiate_protocol(0, ses, server);
15638c8a9a5SSteve French 	if (!rc)
15738c8a9a5SSteve French 		rc = cifs_setup_session(0, ses, server, nls_codepage);
15838c8a9a5SSteve French 
15938c8a9a5SSteve French 	/* do we need to reconnect tcon? */
16038c8a9a5SSteve French 	if (rc || !tcon->need_reconnect) {
16138c8a9a5SSteve French 		mutex_unlock(&ses->session_mutex);
16238c8a9a5SSteve French 		goto out;
16338c8a9a5SSteve French 	}
16438c8a9a5SSteve French 
16538c8a9a5SSteve French skip_sess_setup:
16638c8a9a5SSteve French 	cifs_mark_open_files_invalid(tcon);
16738c8a9a5SSteve French 	rc = cifs_tree_connect(0, tcon, nls_codepage);
16838c8a9a5SSteve French 	mutex_unlock(&ses->session_mutex);
16938c8a9a5SSteve French 	cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
17038c8a9a5SSteve French 
17138c8a9a5SSteve French 	if (rc) {
17238c8a9a5SSteve French 		pr_warn_once("reconnect tcon failed rc = %d\n", rc);
17338c8a9a5SSteve French 		goto out;
17438c8a9a5SSteve French 	}
17538c8a9a5SSteve French 
17638c8a9a5SSteve French 	atomic_inc(&tconInfoReconnectCount);
17738c8a9a5SSteve French 
17838c8a9a5SSteve French 	/* tell server Unix caps we support */
17938c8a9a5SSteve French 	if (cap_unix(ses))
18038c8a9a5SSteve French 		reset_cifs_unix_caps(0, tcon, NULL, NULL);
18138c8a9a5SSteve French 
18238c8a9a5SSteve French 	/*
18338c8a9a5SSteve French 	 * Removed call to reopen open files here. It is safer (and faster) to
18438c8a9a5SSteve French 	 * reopen files one at a time as needed in read and write.
18538c8a9a5SSteve French 	 *
18638c8a9a5SSteve French 	 * FIXME: what about file locks? don't we need to reclaim them ASAP?
18738c8a9a5SSteve French 	 */
18838c8a9a5SSteve French 
18938c8a9a5SSteve French out:
19038c8a9a5SSteve French 	/*
19138c8a9a5SSteve French 	 * Check if handle based operation so we know whether we can continue
19238c8a9a5SSteve French 	 * or not without returning to caller to reset file handle
19338c8a9a5SSteve French 	 */
19438c8a9a5SSteve French 	switch (smb_command) {
19538c8a9a5SSteve French 	case SMB_COM_READ_ANDX:
19638c8a9a5SSteve French 	case SMB_COM_WRITE_ANDX:
19738c8a9a5SSteve French 	case SMB_COM_CLOSE:
19838c8a9a5SSteve French 	case SMB_COM_FIND_CLOSE2:
19938c8a9a5SSteve French 	case SMB_COM_LOCKING_ANDX:
20038c8a9a5SSteve French 		rc = -EAGAIN;
20138c8a9a5SSteve French 	}
20238c8a9a5SSteve French 
20338c8a9a5SSteve French 	return rc;
20438c8a9a5SSteve French }
20538c8a9a5SSteve French 
20638c8a9a5SSteve French /* Allocate and return pointer to an SMB request buffer, and set basic
20738c8a9a5SSteve French    SMB information in the SMB header.  If the return code is zero, this
20838c8a9a5SSteve French    function must have filled in request_buf pointer */
20938c8a9a5SSteve French static int
small_smb_init(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf)21038c8a9a5SSteve French small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
21138c8a9a5SSteve French 		void **request_buf)
21238c8a9a5SSteve French {
21338c8a9a5SSteve French 	int rc;
21438c8a9a5SSteve French 
21538c8a9a5SSteve French 	rc = cifs_reconnect_tcon(tcon, smb_command);
21638c8a9a5SSteve French 	if (rc)
21738c8a9a5SSteve French 		return rc;
21838c8a9a5SSteve French 
21938c8a9a5SSteve French 	*request_buf = cifs_small_buf_get();
22038c8a9a5SSteve French 	if (*request_buf == NULL) {
22138c8a9a5SSteve French 		/* BB should we add a retry in here if not a writepage? */
22238c8a9a5SSteve French 		return -ENOMEM;
22338c8a9a5SSteve French 	}
22438c8a9a5SSteve French 
22538c8a9a5SSteve French 	header_assemble((struct smb_hdr *) *request_buf, smb_command,
22638c8a9a5SSteve French 			tcon, wct);
22738c8a9a5SSteve French 
22838c8a9a5SSteve French 	if (tcon != NULL)
22938c8a9a5SSteve French 		cifs_stats_inc(&tcon->num_smbs_sent);
23038c8a9a5SSteve French 
23138c8a9a5SSteve French 	return 0;
23238c8a9a5SSteve French }
23338c8a9a5SSteve French 
23438c8a9a5SSteve French int
small_smb_init_no_tc(const int smb_command,const int wct,struct cifs_ses * ses,void ** request_buf)23538c8a9a5SSteve French small_smb_init_no_tc(const int smb_command, const int wct,
23638c8a9a5SSteve French 		     struct cifs_ses *ses, void **request_buf)
23738c8a9a5SSteve French {
23838c8a9a5SSteve French 	int rc;
23938c8a9a5SSteve French 	struct smb_hdr *buffer;
24038c8a9a5SSteve French 
24138c8a9a5SSteve French 	rc = small_smb_init(smb_command, wct, NULL, request_buf);
24238c8a9a5SSteve French 	if (rc)
24338c8a9a5SSteve French 		return rc;
24438c8a9a5SSteve French 
24538c8a9a5SSteve French 	buffer = (struct smb_hdr *)*request_buf;
24638c8a9a5SSteve French 	buffer->Mid = get_next_mid(ses->server);
24738c8a9a5SSteve French 	if (ses->capabilities & CAP_UNICODE)
24838c8a9a5SSteve French 		buffer->Flags2 |= SMBFLG2_UNICODE;
24938c8a9a5SSteve French 	if (ses->capabilities & CAP_STATUS32)
25038c8a9a5SSteve French 		buffer->Flags2 |= SMBFLG2_ERR_STATUS;
25138c8a9a5SSteve French 
25238c8a9a5SSteve French 	/* uid, tid can stay at zero as set in header assemble */
25338c8a9a5SSteve French 
25438c8a9a5SSteve French 	/* BB add support for turning on the signing when
25538c8a9a5SSteve French 	this function is used after 1st of session setup requests */
25638c8a9a5SSteve French 
25738c8a9a5SSteve French 	return rc;
25838c8a9a5SSteve French }
25938c8a9a5SSteve French 
26038c8a9a5SSteve French /* If the return code is zero, this function must fill in request_buf pointer */
26138c8a9a5SSteve French static int
__smb_init(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf,void ** response_buf)26238c8a9a5SSteve French __smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
26338c8a9a5SSteve French 			void **request_buf, void **response_buf)
26438c8a9a5SSteve French {
26538c8a9a5SSteve French 	*request_buf = cifs_buf_get();
26638c8a9a5SSteve French 	if (*request_buf == NULL) {
26738c8a9a5SSteve French 		/* BB should we add a retry in here if not a writepage? */
26838c8a9a5SSteve French 		return -ENOMEM;
26938c8a9a5SSteve French 	}
27038c8a9a5SSteve French     /* Although the original thought was we needed the response buf for  */
27138c8a9a5SSteve French     /* potential retries of smb operations it turns out we can determine */
27238c8a9a5SSteve French     /* from the mid flags when the request buffer can be resent without  */
27338c8a9a5SSteve French     /* having to use a second distinct buffer for the response */
27438c8a9a5SSteve French 	if (response_buf)
27538c8a9a5SSteve French 		*response_buf = *request_buf;
27638c8a9a5SSteve French 
27738c8a9a5SSteve French 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
27838c8a9a5SSteve French 			wct);
27938c8a9a5SSteve French 
28038c8a9a5SSteve French 	if (tcon != NULL)
28138c8a9a5SSteve French 		cifs_stats_inc(&tcon->num_smbs_sent);
28238c8a9a5SSteve French 
28338c8a9a5SSteve French 	return 0;
28438c8a9a5SSteve French }
28538c8a9a5SSteve French 
28638c8a9a5SSteve French /* If the return code is zero, this function must fill in request_buf pointer */
28738c8a9a5SSteve French static int
smb_init(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf,void ** response_buf)28838c8a9a5SSteve French smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
28938c8a9a5SSteve French 	 void **request_buf, void **response_buf)
29038c8a9a5SSteve French {
29138c8a9a5SSteve French 	int rc;
29238c8a9a5SSteve French 
29338c8a9a5SSteve French 	rc = cifs_reconnect_tcon(tcon, smb_command);
29438c8a9a5SSteve French 	if (rc)
29538c8a9a5SSteve French 		return rc;
29638c8a9a5SSteve French 
29738c8a9a5SSteve French 	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
29838c8a9a5SSteve French }
29938c8a9a5SSteve French 
30038c8a9a5SSteve French static int
smb_init_no_reconnect(int smb_command,int wct,struct cifs_tcon * tcon,void ** request_buf,void ** response_buf)30138c8a9a5SSteve French smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
30238c8a9a5SSteve French 			void **request_buf, void **response_buf)
30338c8a9a5SSteve French {
30438c8a9a5SSteve French 	spin_lock(&tcon->ses->chan_lock);
30538c8a9a5SSteve French 	if (cifs_chan_needs_reconnect(tcon->ses, tcon->ses->server) ||
30638c8a9a5SSteve French 	    tcon->need_reconnect) {
30738c8a9a5SSteve French 		spin_unlock(&tcon->ses->chan_lock);
30838c8a9a5SSteve French 		return -EHOSTDOWN;
30938c8a9a5SSteve French 	}
31038c8a9a5SSteve French 	spin_unlock(&tcon->ses->chan_lock);
31138c8a9a5SSteve French 
31238c8a9a5SSteve French 	return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
31338c8a9a5SSteve French }
31438c8a9a5SSteve French 
validate_t2(struct smb_t2_rsp * pSMB)31538c8a9a5SSteve French static int validate_t2(struct smb_t2_rsp *pSMB)
31638c8a9a5SSteve French {
31738c8a9a5SSteve French 	unsigned int total_size;
31838c8a9a5SSteve French 
31938c8a9a5SSteve French 	/* check for plausible wct */
32038c8a9a5SSteve French 	if (pSMB->hdr.WordCount < 10)
32138c8a9a5SSteve French 		goto vt2_err;
32238c8a9a5SSteve French 
32338c8a9a5SSteve French 	/* check for parm and data offset going beyond end of smb */
32438c8a9a5SSteve French 	if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
32538c8a9a5SSteve French 	    get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
32638c8a9a5SSteve French 		goto vt2_err;
32738c8a9a5SSteve French 
32838c8a9a5SSteve French 	total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
32938c8a9a5SSteve French 	if (total_size >= 512)
33038c8a9a5SSteve French 		goto vt2_err;
33138c8a9a5SSteve French 
33238c8a9a5SSteve French 	/* check that bcc is at least as big as parms + data, and that it is
33338c8a9a5SSteve French 	 * less than negotiated smb buffer
33438c8a9a5SSteve French 	 */
33538c8a9a5SSteve French 	total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
33638c8a9a5SSteve French 	if (total_size > get_bcc(&pSMB->hdr) ||
33738c8a9a5SSteve French 	    total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
33838c8a9a5SSteve French 		goto vt2_err;
33938c8a9a5SSteve French 
34038c8a9a5SSteve French 	return 0;
34138c8a9a5SSteve French vt2_err:
34238c8a9a5SSteve French 	cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
34338c8a9a5SSteve French 		sizeof(struct smb_t2_rsp) + 16);
34438c8a9a5SSteve French 	return -EINVAL;
34538c8a9a5SSteve French }
34638c8a9a5SSteve French 
34738c8a9a5SSteve French static int
decode_ext_sec_blob(struct cifs_ses * ses,NEGOTIATE_RSP * pSMBr)34838c8a9a5SSteve French decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
34938c8a9a5SSteve French {
35038c8a9a5SSteve French 	int	rc = 0;
35138c8a9a5SSteve French 	u16	count;
35238c8a9a5SSteve French 	char	*guid = pSMBr->u.extended_response.GUID;
35338c8a9a5SSteve French 	struct TCP_Server_Info *server = ses->server;
35438c8a9a5SSteve French 
35538c8a9a5SSteve French 	count = get_bcc(&pSMBr->hdr);
35638c8a9a5SSteve French 	if (count < SMB1_CLIENT_GUID_SIZE)
35738c8a9a5SSteve French 		return -EIO;
35838c8a9a5SSteve French 
35938c8a9a5SSteve French 	spin_lock(&cifs_tcp_ses_lock);
36038c8a9a5SSteve French 	if (server->srv_count > 1) {
36138c8a9a5SSteve French 		spin_unlock(&cifs_tcp_ses_lock);
36238c8a9a5SSteve French 		if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
36338c8a9a5SSteve French 			cifs_dbg(FYI, "server UID changed\n");
36438c8a9a5SSteve French 			memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
36538c8a9a5SSteve French 		}
36638c8a9a5SSteve French 	} else {
36738c8a9a5SSteve French 		spin_unlock(&cifs_tcp_ses_lock);
36838c8a9a5SSteve French 		memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
36938c8a9a5SSteve French 	}
37038c8a9a5SSteve French 
37138c8a9a5SSteve French 	if (count == SMB1_CLIENT_GUID_SIZE) {
37238c8a9a5SSteve French 		server->sec_ntlmssp = true;
37338c8a9a5SSteve French 	} else {
37438c8a9a5SSteve French 		count -= SMB1_CLIENT_GUID_SIZE;
37538c8a9a5SSteve French 		rc = decode_negTokenInit(
37638c8a9a5SSteve French 			pSMBr->u.extended_response.SecurityBlob, count, server);
37738c8a9a5SSteve French 		if (rc != 1)
37838c8a9a5SSteve French 			return -EINVAL;
37938c8a9a5SSteve French 	}
38038c8a9a5SSteve French 
38138c8a9a5SSteve French 	return 0;
38238c8a9a5SSteve French }
38338c8a9a5SSteve French 
38438c8a9a5SSteve French static bool
should_set_ext_sec_flag(enum securityEnum sectype)38538c8a9a5SSteve French should_set_ext_sec_flag(enum securityEnum sectype)
38638c8a9a5SSteve French {
38738c8a9a5SSteve French 	switch (sectype) {
38838c8a9a5SSteve French 	case RawNTLMSSP:
38938c8a9a5SSteve French 	case Kerberos:
39038c8a9a5SSteve French 		return true;
39138c8a9a5SSteve French 	case Unspecified:
39238c8a9a5SSteve French 		if (global_secflags &
39338c8a9a5SSteve French 		    (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
39438c8a9a5SSteve French 			return true;
39538c8a9a5SSteve French 		fallthrough;
39638c8a9a5SSteve French 	default:
39738c8a9a5SSteve French 		return false;
39838c8a9a5SSteve French 	}
39938c8a9a5SSteve French }
40038c8a9a5SSteve French 
40138c8a9a5SSteve French int
CIFSSMBNegotiate(const unsigned int xid,struct cifs_ses * ses,struct TCP_Server_Info * server)40238c8a9a5SSteve French CIFSSMBNegotiate(const unsigned int xid,
40338c8a9a5SSteve French 		 struct cifs_ses *ses,
40438c8a9a5SSteve French 		 struct TCP_Server_Info *server)
40538c8a9a5SSteve French {
40638c8a9a5SSteve French 	NEGOTIATE_REQ *pSMB;
40738c8a9a5SSteve French 	NEGOTIATE_RSP *pSMBr;
40838c8a9a5SSteve French 	int rc = 0;
40938c8a9a5SSteve French 	int bytes_returned;
41038c8a9a5SSteve French 	int i;
41138c8a9a5SSteve French 	u16 count;
41238c8a9a5SSteve French 
41338c8a9a5SSteve French 	if (!server) {
41438c8a9a5SSteve French 		WARN(1, "%s: server is NULL!\n", __func__);
41538c8a9a5SSteve French 		return -EIO;
41638c8a9a5SSteve French 	}
41738c8a9a5SSteve French 
41838c8a9a5SSteve French 	rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
41938c8a9a5SSteve French 		      (void **) &pSMB, (void **) &pSMBr);
42038c8a9a5SSteve French 	if (rc)
42138c8a9a5SSteve French 		return rc;
42238c8a9a5SSteve French 
42338c8a9a5SSteve French 	pSMB->hdr.Mid = get_next_mid(server);
42438c8a9a5SSteve French 	pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
42538c8a9a5SSteve French 
42638c8a9a5SSteve French 	if (should_set_ext_sec_flag(ses->sectype)) {
42738c8a9a5SSteve French 		cifs_dbg(FYI, "Requesting extended security\n");
42838c8a9a5SSteve French 		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
42938c8a9a5SSteve French 	}
43038c8a9a5SSteve French 
43138c8a9a5SSteve French 	count = 0;
43238c8a9a5SSteve French 	/*
43338c8a9a5SSteve French 	 * We know that all the name entries in the protocols array
43438c8a9a5SSteve French 	 * are short (< 16 bytes anyway) and are NUL terminated.
43538c8a9a5SSteve French 	 */
43638c8a9a5SSteve French 	for (i = 0; i < CIFS_NUM_PROT; i++) {
43738c8a9a5SSteve French 		size_t len = strlen(protocols[i].name) + 1;
43838c8a9a5SSteve French 
43938c8a9a5SSteve French 		memcpy(&pSMB->DialectsArray[count], protocols[i].name, len);
44038c8a9a5SSteve French 		count += len;
44138c8a9a5SSteve French 	}
44238c8a9a5SSteve French 	inc_rfc1001_len(pSMB, count);
44338c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(count);
44438c8a9a5SSteve French 
44538c8a9a5SSteve French 	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
44638c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
44738c8a9a5SSteve French 	if (rc != 0)
44838c8a9a5SSteve French 		goto neg_err_exit;
44938c8a9a5SSteve French 
45038c8a9a5SSteve French 	server->dialect = le16_to_cpu(pSMBr->DialectIndex);
45138c8a9a5SSteve French 	cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
45238c8a9a5SSteve French 	/* Check wct = 1 error case */
45338c8a9a5SSteve French 	if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) {
45438c8a9a5SSteve French 		/* core returns wct = 1, but we do not ask for core - otherwise
45538c8a9a5SSteve French 		small wct just comes when dialect index is -1 indicating we
45638c8a9a5SSteve French 		could not negotiate a common dialect */
45738c8a9a5SSteve French 		rc = -EOPNOTSUPP;
45838c8a9a5SSteve French 		goto neg_err_exit;
45938c8a9a5SSteve French 	} else if (pSMBr->hdr.WordCount != 17) {
46038c8a9a5SSteve French 		/* unknown wct */
46138c8a9a5SSteve French 		rc = -EOPNOTSUPP;
46238c8a9a5SSteve French 		goto neg_err_exit;
46338c8a9a5SSteve French 	}
46438c8a9a5SSteve French 	/* else wct == 17, NTLM or better */
46538c8a9a5SSteve French 
46638c8a9a5SSteve French 	server->sec_mode = pSMBr->SecurityMode;
46738c8a9a5SSteve French 	if ((server->sec_mode & SECMODE_USER) == 0)
46838c8a9a5SSteve French 		cifs_dbg(FYI, "share mode security\n");
46938c8a9a5SSteve French 
47038c8a9a5SSteve French 	/* one byte, so no need to convert this or EncryptionKeyLen from
47138c8a9a5SSteve French 	   little endian */
47238c8a9a5SSteve French 	server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
47338c8a9a5SSteve French 			       cifs_max_pending);
47438c8a9a5SSteve French 	set_credits(server, server->maxReq);
47538c8a9a5SSteve French 	/* probably no need to store and check maxvcs */
47638c8a9a5SSteve French 	server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
47738c8a9a5SSteve French 	/* set up max_read for readahead check */
47838c8a9a5SSteve French 	server->max_read = server->maxBuf;
47938c8a9a5SSteve French 	server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
48038c8a9a5SSteve French 	cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
48138c8a9a5SSteve French 	server->capabilities = le32_to_cpu(pSMBr->Capabilities);
48238c8a9a5SSteve French 	server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
48338c8a9a5SSteve French 	server->timeAdj *= 60;
48438c8a9a5SSteve French 
48538c8a9a5SSteve French 	if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
48638c8a9a5SSteve French 		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
48738c8a9a5SSteve French 		memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
48838c8a9a5SSteve French 		       CIFS_CRYPTO_KEY_SIZE);
48938c8a9a5SSteve French 	} else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
49038c8a9a5SSteve French 			server->capabilities & CAP_EXTENDED_SECURITY) {
49138c8a9a5SSteve French 		server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
49238c8a9a5SSteve French 		rc = decode_ext_sec_blob(ses, pSMBr);
49338c8a9a5SSteve French 	} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
49438c8a9a5SSteve French 		rc = -EIO; /* no crypt key only if plain text pwd */
49538c8a9a5SSteve French 	} else {
49638c8a9a5SSteve French 		server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
49738c8a9a5SSteve French 		server->capabilities &= ~CAP_EXTENDED_SECURITY;
49838c8a9a5SSteve French 	}
49938c8a9a5SSteve French 
50038c8a9a5SSteve French 	if (!rc)
50138c8a9a5SSteve French 		rc = cifs_enable_signing(server, ses->sign);
50238c8a9a5SSteve French neg_err_exit:
50338c8a9a5SSteve French 	cifs_buf_release(pSMB);
50438c8a9a5SSteve French 
50538c8a9a5SSteve French 	cifs_dbg(FYI, "negprot rc %d\n", rc);
50638c8a9a5SSteve French 	return rc;
50738c8a9a5SSteve French }
50838c8a9a5SSteve French 
50938c8a9a5SSteve French int
CIFSSMBTDis(const unsigned int xid,struct cifs_tcon * tcon)51038c8a9a5SSteve French CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
51138c8a9a5SSteve French {
51238c8a9a5SSteve French 	struct smb_hdr *smb_buffer;
51338c8a9a5SSteve French 	int rc = 0;
51438c8a9a5SSteve French 
51538c8a9a5SSteve French 	cifs_dbg(FYI, "In tree disconnect\n");
51638c8a9a5SSteve French 
51738c8a9a5SSteve French 	/* BB: do we need to check this? These should never be NULL. */
51838c8a9a5SSteve French 	if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
51938c8a9a5SSteve French 		return -EIO;
52038c8a9a5SSteve French 
52138c8a9a5SSteve French 	/*
52238c8a9a5SSteve French 	 * No need to return error on this operation if tid invalidated and
52338c8a9a5SSteve French 	 * closed on server already e.g. due to tcp session crashing. Also,
52438c8a9a5SSteve French 	 * the tcon is no longer on the list, so no need to take lock before
52538c8a9a5SSteve French 	 * checking this.
52638c8a9a5SSteve French 	 */
52738c8a9a5SSteve French 	spin_lock(&tcon->ses->chan_lock);
52838c8a9a5SSteve French 	if ((tcon->need_reconnect) || CIFS_ALL_CHANS_NEED_RECONNECT(tcon->ses)) {
52938c8a9a5SSteve French 		spin_unlock(&tcon->ses->chan_lock);
53038c8a9a5SSteve French 		return -EIO;
53138c8a9a5SSteve French 	}
53238c8a9a5SSteve French 	spin_unlock(&tcon->ses->chan_lock);
53338c8a9a5SSteve French 
53438c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
53538c8a9a5SSteve French 			    (void **)&smb_buffer);
53638c8a9a5SSteve French 	if (rc)
53738c8a9a5SSteve French 		return rc;
53838c8a9a5SSteve French 
53938c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
54038c8a9a5SSteve French 	cifs_small_buf_release(smb_buffer);
54138c8a9a5SSteve French 	if (rc)
54238c8a9a5SSteve French 		cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
54338c8a9a5SSteve French 
54438c8a9a5SSteve French 	/* No need to return error on this operation if tid invalidated and
54538c8a9a5SSteve French 	   closed on server already e.g. due to tcp session crashing */
54638c8a9a5SSteve French 	if (rc == -EAGAIN)
54738c8a9a5SSteve French 		rc = 0;
54838c8a9a5SSteve French 
54938c8a9a5SSteve French 	return rc;
55038c8a9a5SSteve French }
55138c8a9a5SSteve French 
55238c8a9a5SSteve French /*
55338c8a9a5SSteve French  * This is a no-op for now. We're not really interested in the reply, but
55438c8a9a5SSteve French  * rather in the fact that the server sent one and that server->lstrp
55538c8a9a5SSteve French  * gets updated.
55638c8a9a5SSteve French  *
55738c8a9a5SSteve French  * FIXME: maybe we should consider checking that the reply matches request?
55838c8a9a5SSteve French  */
55938c8a9a5SSteve French static void
cifs_echo_callback(struct mid_q_entry * mid)56038c8a9a5SSteve French cifs_echo_callback(struct mid_q_entry *mid)
56138c8a9a5SSteve French {
56238c8a9a5SSteve French 	struct TCP_Server_Info *server = mid->callback_data;
56338c8a9a5SSteve French 	struct cifs_credits credits = { .value = 1, .instance = 0 };
56438c8a9a5SSteve French 
56538c8a9a5SSteve French 	release_mid(mid);
56638c8a9a5SSteve French 	add_credits(server, &credits, CIFS_ECHO_OP);
56738c8a9a5SSteve French }
56838c8a9a5SSteve French 
56938c8a9a5SSteve French int
CIFSSMBEcho(struct TCP_Server_Info * server)57038c8a9a5SSteve French CIFSSMBEcho(struct TCP_Server_Info *server)
57138c8a9a5SSteve French {
57238c8a9a5SSteve French 	ECHO_REQ *smb;
57338c8a9a5SSteve French 	int rc = 0;
57438c8a9a5SSteve French 	struct kvec iov[2];
57538c8a9a5SSteve French 	struct smb_rqst rqst = { .rq_iov = iov,
57638c8a9a5SSteve French 				 .rq_nvec = 2 };
57738c8a9a5SSteve French 
57838c8a9a5SSteve French 	cifs_dbg(FYI, "In echo request\n");
57938c8a9a5SSteve French 
58038c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
58138c8a9a5SSteve French 	if (rc)
58238c8a9a5SSteve French 		return rc;
58338c8a9a5SSteve French 
58438c8a9a5SSteve French 	if (server->capabilities & CAP_UNICODE)
58538c8a9a5SSteve French 		smb->hdr.Flags2 |= SMBFLG2_UNICODE;
58638c8a9a5SSteve French 
58738c8a9a5SSteve French 	/* set up echo request */
58838c8a9a5SSteve French 	smb->hdr.Tid = 0xffff;
58938c8a9a5SSteve French 	smb->hdr.WordCount = 1;
59038c8a9a5SSteve French 	put_unaligned_le16(1, &smb->EchoCount);
59138c8a9a5SSteve French 	put_bcc(1, &smb->hdr);
59238c8a9a5SSteve French 	smb->Data[0] = 'a';
59338c8a9a5SSteve French 	inc_rfc1001_len(smb, 3);
59438c8a9a5SSteve French 
59538c8a9a5SSteve French 	iov[0].iov_len = 4;
59638c8a9a5SSteve French 	iov[0].iov_base = smb;
59738c8a9a5SSteve French 	iov[1].iov_len = get_rfc1002_length(smb);
59838c8a9a5SSteve French 	iov[1].iov_base = (char *)smb + 4;
59938c8a9a5SSteve French 
60038c8a9a5SSteve French 	rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
60138c8a9a5SSteve French 			     server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL);
60238c8a9a5SSteve French 	if (rc)
60338c8a9a5SSteve French 		cifs_dbg(FYI, "Echo request failed: %d\n", rc);
60438c8a9a5SSteve French 
60538c8a9a5SSteve French 	cifs_small_buf_release(smb);
60638c8a9a5SSteve French 
60738c8a9a5SSteve French 	return rc;
60838c8a9a5SSteve French }
60938c8a9a5SSteve French 
61038c8a9a5SSteve French int
CIFSSMBLogoff(const unsigned int xid,struct cifs_ses * ses)61138c8a9a5SSteve French CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
61238c8a9a5SSteve French {
61338c8a9a5SSteve French 	LOGOFF_ANDX_REQ *pSMB;
61438c8a9a5SSteve French 	int rc = 0;
61538c8a9a5SSteve French 
61638c8a9a5SSteve French 	cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
61738c8a9a5SSteve French 
61838c8a9a5SSteve French 	/*
61938c8a9a5SSteve French 	 * BB: do we need to check validity of ses and server? They should
62038c8a9a5SSteve French 	 * always be valid since we have an active reference. If not, that
62138c8a9a5SSteve French 	 * should probably be a BUG()
62238c8a9a5SSteve French 	 */
62338c8a9a5SSteve French 	if (!ses || !ses->server)
62438c8a9a5SSteve French 		return -EIO;
62538c8a9a5SSteve French 
62638c8a9a5SSteve French 	mutex_lock(&ses->session_mutex);
62738c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
62838c8a9a5SSteve French 	if (CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
62938c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
63038c8a9a5SSteve French 		goto session_already_dead; /* no need to send SMBlogoff if uid
63138c8a9a5SSteve French 					      already closed due to reconnect */
63238c8a9a5SSteve French 	}
63338c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
63438c8a9a5SSteve French 
63538c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
63638c8a9a5SSteve French 	if (rc) {
63738c8a9a5SSteve French 		mutex_unlock(&ses->session_mutex);
63838c8a9a5SSteve French 		return rc;
63938c8a9a5SSteve French 	}
64038c8a9a5SSteve French 
64138c8a9a5SSteve French 	pSMB->hdr.Mid = get_next_mid(ses->server);
64238c8a9a5SSteve French 
64338c8a9a5SSteve French 	if (ses->server->sign)
64438c8a9a5SSteve French 		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
64538c8a9a5SSteve French 
64638c8a9a5SSteve French 	pSMB->hdr.Uid = ses->Suid;
64738c8a9a5SSteve French 
64838c8a9a5SSteve French 	pSMB->AndXCommand = 0xFF;
64938c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
65038c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
65138c8a9a5SSteve French session_already_dead:
65238c8a9a5SSteve French 	mutex_unlock(&ses->session_mutex);
65338c8a9a5SSteve French 
65438c8a9a5SSteve French 	/* if session dead then we do not need to do ulogoff,
65538c8a9a5SSteve French 		since server closed smb session, no sense reporting
65638c8a9a5SSteve French 		error */
65738c8a9a5SSteve French 	if (rc == -EAGAIN)
65838c8a9a5SSteve French 		rc = 0;
65938c8a9a5SSteve French 	return rc;
66038c8a9a5SSteve French }
66138c8a9a5SSteve French 
66238c8a9a5SSteve French int
CIFSPOSIXDelFile(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,__u16 type,const struct nls_table * nls_codepage,int remap)66338c8a9a5SSteve French CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
66438c8a9a5SSteve French 		 const char *fileName, __u16 type,
66538c8a9a5SSteve French 		 const struct nls_table *nls_codepage, int remap)
66638c8a9a5SSteve French {
66738c8a9a5SSteve French 	TRANSACTION2_SPI_REQ *pSMB = NULL;
66838c8a9a5SSteve French 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
66938c8a9a5SSteve French 	struct unlink_psx_rq *pRqD;
67038c8a9a5SSteve French 	int name_len;
67138c8a9a5SSteve French 	int rc = 0;
67238c8a9a5SSteve French 	int bytes_returned = 0;
67338c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count;
67438c8a9a5SSteve French 
67538c8a9a5SSteve French 	cifs_dbg(FYI, "In POSIX delete\n");
67638c8a9a5SSteve French PsxDelete:
67738c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
67838c8a9a5SSteve French 		      (void **) &pSMBr);
67938c8a9a5SSteve French 	if (rc)
68038c8a9a5SSteve French 		return rc;
68138c8a9a5SSteve French 
68238c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
68338c8a9a5SSteve French 		name_len =
68438c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
68538c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
68638c8a9a5SSteve French 		name_len++;	/* trailing null */
68738c8a9a5SSteve French 		name_len *= 2;
68838c8a9a5SSteve French 	} else {
68938c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, fileName);
69038c8a9a5SSteve French 	}
69138c8a9a5SSteve French 
69238c8a9a5SSteve French 	params = 6 + name_len;
69338c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
69438c8a9a5SSteve French 	pSMB->MaxDataCount = 0; /* BB double check this with jra */
69538c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
69638c8a9a5SSteve French 	pSMB->Reserved = 0;
69738c8a9a5SSteve French 	pSMB->Flags = 0;
69838c8a9a5SSteve French 	pSMB->Timeout = 0;
69938c8a9a5SSteve French 	pSMB->Reserved2 = 0;
70038c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
70138c8a9a5SSteve French 				InformationLevel) - 4;
70238c8a9a5SSteve French 	offset = param_offset + params;
70338c8a9a5SSteve French 
70438c8a9a5SSteve French 	/* Setup pointer to Request Data (inode type).
70538c8a9a5SSteve French 	 * Note that SMB offsets are from the beginning of SMB which is 4 bytes
70638c8a9a5SSteve French 	 * in, after RFC1001 field
70738c8a9a5SSteve French 	 */
70838c8a9a5SSteve French 	pRqD = (struct unlink_psx_rq *)((char *)(pSMB) + offset + 4);
70938c8a9a5SSteve French 	pRqD->type = cpu_to_le16(type);
71038c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
71138c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
71238c8a9a5SSteve French 	pSMB->SetupCount = 1;
71338c8a9a5SSteve French 	pSMB->Reserved3 = 0;
71438c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
71538c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + sizeof(struct unlink_psx_rq);
71638c8a9a5SSteve French 
71738c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
71838c8a9a5SSteve French 	pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
71938c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
72038c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
72138c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
72238c8a9a5SSteve French 	pSMB->Reserved4 = 0;
72338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
72438c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
72538c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
72638c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
72738c8a9a5SSteve French 	if (rc)
72838c8a9a5SSteve French 		cifs_dbg(FYI, "Posix delete returned %d\n", rc);
72938c8a9a5SSteve French 	cifs_buf_release(pSMB);
73038c8a9a5SSteve French 
73138c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
73238c8a9a5SSteve French 
73338c8a9a5SSteve French 	if (rc == -EAGAIN)
73438c8a9a5SSteve French 		goto PsxDelete;
73538c8a9a5SSteve French 
73638c8a9a5SSteve French 	return rc;
73738c8a9a5SSteve French }
73838c8a9a5SSteve French 
73938c8a9a5SSteve French int
CIFSSMBDelFile(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb,struct dentry * dentry)74038c8a9a5SSteve French CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
741f93d145fSMeetakshi Setiya 	       struct cifs_sb_info *cifs_sb, struct dentry *dentry)
74238c8a9a5SSteve French {
74338c8a9a5SSteve French 	DELETE_FILE_REQ *pSMB = NULL;
74438c8a9a5SSteve French 	DELETE_FILE_RSP *pSMBr = NULL;
74538c8a9a5SSteve French 	int rc = 0;
74638c8a9a5SSteve French 	int bytes_returned;
74738c8a9a5SSteve French 	int name_len;
74838c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
74938c8a9a5SSteve French 
75038c8a9a5SSteve French DelFileRetry:
75138c8a9a5SSteve French 	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
75238c8a9a5SSteve French 		      (void **) &pSMBr);
75338c8a9a5SSteve French 	if (rc)
75438c8a9a5SSteve French 		return rc;
75538c8a9a5SSteve French 
75638c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
75738c8a9a5SSteve French 		name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
75838c8a9a5SSteve French 					      PATH_MAX, cifs_sb->local_nls,
75938c8a9a5SSteve French 					      remap);
76038c8a9a5SSteve French 		name_len++;	/* trailing null */
76138c8a9a5SSteve French 		name_len *= 2;
76238c8a9a5SSteve French 	} else {
76338c8a9a5SSteve French 		name_len = copy_path_name(pSMB->fileName, name);
76438c8a9a5SSteve French 	}
76538c8a9a5SSteve French 	pSMB->SearchAttributes =
76638c8a9a5SSteve French 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
76738c8a9a5SSteve French 	pSMB->BufferFormat = 0x04;
76838c8a9a5SSteve French 	inc_rfc1001_len(pSMB, name_len + 1);
76938c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
77038c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
77138c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
77238c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
77338c8a9a5SSteve French 	if (rc)
77438c8a9a5SSteve French 		cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
77538c8a9a5SSteve French 
77638c8a9a5SSteve French 	cifs_buf_release(pSMB);
77738c8a9a5SSteve French 	if (rc == -EAGAIN)
77838c8a9a5SSteve French 		goto DelFileRetry;
77938c8a9a5SSteve French 
78038c8a9a5SSteve French 	return rc;
78138c8a9a5SSteve French }
78238c8a9a5SSteve French 
78338c8a9a5SSteve French int
CIFSSMBRmDir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)78438c8a9a5SSteve French CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
78538c8a9a5SSteve French 	     struct cifs_sb_info *cifs_sb)
78638c8a9a5SSteve French {
78738c8a9a5SSteve French 	DELETE_DIRECTORY_REQ *pSMB = NULL;
78838c8a9a5SSteve French 	DELETE_DIRECTORY_RSP *pSMBr = NULL;
78938c8a9a5SSteve French 	int rc = 0;
79038c8a9a5SSteve French 	int bytes_returned;
79138c8a9a5SSteve French 	int name_len;
79238c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
79338c8a9a5SSteve French 
79438c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSSMBRmDir\n");
79538c8a9a5SSteve French RmDirRetry:
79638c8a9a5SSteve French 	rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
79738c8a9a5SSteve French 		      (void **) &pSMBr);
79838c8a9a5SSteve French 	if (rc)
79938c8a9a5SSteve French 		return rc;
80038c8a9a5SSteve French 
80138c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
80238c8a9a5SSteve French 		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
80338c8a9a5SSteve French 					      PATH_MAX, cifs_sb->local_nls,
80438c8a9a5SSteve French 					      remap);
80538c8a9a5SSteve French 		name_len++;	/* trailing null */
80638c8a9a5SSteve French 		name_len *= 2;
80738c8a9a5SSteve French 	} else {
80838c8a9a5SSteve French 		name_len = copy_path_name(pSMB->DirName, name);
80938c8a9a5SSteve French 	}
81038c8a9a5SSteve French 
81138c8a9a5SSteve French 	pSMB->BufferFormat = 0x04;
81238c8a9a5SSteve French 	inc_rfc1001_len(pSMB, name_len + 1);
81338c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
81438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
81538c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
81638c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
81738c8a9a5SSteve French 	if (rc)
81838c8a9a5SSteve French 		cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
81938c8a9a5SSteve French 
82038c8a9a5SSteve French 	cifs_buf_release(pSMB);
82138c8a9a5SSteve French 	if (rc == -EAGAIN)
82238c8a9a5SSteve French 		goto RmDirRetry;
82338c8a9a5SSteve French 	return rc;
82438c8a9a5SSteve French }
82538c8a9a5SSteve French 
82638c8a9a5SSteve French int
CIFSSMBMkDir(const unsigned int xid,struct inode * inode,umode_t mode,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)82738c8a9a5SSteve French CIFSSMBMkDir(const unsigned int xid, struct inode *inode, umode_t mode,
82838c8a9a5SSteve French 	     struct cifs_tcon *tcon, const char *name,
82938c8a9a5SSteve French 	     struct cifs_sb_info *cifs_sb)
83038c8a9a5SSteve French {
83138c8a9a5SSteve French 	int rc = 0;
83238c8a9a5SSteve French 	CREATE_DIRECTORY_REQ *pSMB = NULL;
83338c8a9a5SSteve French 	CREATE_DIRECTORY_RSP *pSMBr = NULL;
83438c8a9a5SSteve French 	int bytes_returned;
83538c8a9a5SSteve French 	int name_len;
83638c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
83738c8a9a5SSteve French 
83838c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSSMBMkDir\n");
83938c8a9a5SSteve French MkDirRetry:
84038c8a9a5SSteve French 	rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
84138c8a9a5SSteve French 		      (void **) &pSMBr);
84238c8a9a5SSteve French 	if (rc)
84338c8a9a5SSteve French 		return rc;
84438c8a9a5SSteve French 
84538c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
84638c8a9a5SSteve French 		name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
84738c8a9a5SSteve French 					      PATH_MAX, cifs_sb->local_nls,
84838c8a9a5SSteve French 					      remap);
84938c8a9a5SSteve French 		name_len++;	/* trailing null */
85038c8a9a5SSteve French 		name_len *= 2;
85138c8a9a5SSteve French 	} else {
85238c8a9a5SSteve French 		name_len = copy_path_name(pSMB->DirName, name);
85338c8a9a5SSteve French 	}
85438c8a9a5SSteve French 
85538c8a9a5SSteve French 	pSMB->BufferFormat = 0x04;
85638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, name_len + 1);
85738c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(name_len + 1);
85838c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
85938c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
86038c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
86138c8a9a5SSteve French 	if (rc)
86238c8a9a5SSteve French 		cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
86338c8a9a5SSteve French 
86438c8a9a5SSteve French 	cifs_buf_release(pSMB);
86538c8a9a5SSteve French 	if (rc == -EAGAIN)
86638c8a9a5SSteve French 		goto MkDirRetry;
86738c8a9a5SSteve French 	return rc;
86838c8a9a5SSteve French }
86938c8a9a5SSteve French 
87038c8a9a5SSteve French int
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)87138c8a9a5SSteve French CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
87238c8a9a5SSteve French 		__u32 posix_flags, __u64 mode, __u16 *netfid,
87338c8a9a5SSteve French 		FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
87438c8a9a5SSteve French 		const char *name, const struct nls_table *nls_codepage,
87538c8a9a5SSteve French 		int remap)
87638c8a9a5SSteve French {
87738c8a9a5SSteve French 	TRANSACTION2_SPI_REQ *pSMB = NULL;
87838c8a9a5SSteve French 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
87938c8a9a5SSteve French 	int name_len;
88038c8a9a5SSteve French 	int rc = 0;
88138c8a9a5SSteve French 	int bytes_returned = 0;
88238c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count, count;
88338c8a9a5SSteve French 	OPEN_PSX_REQ *pdata;
88438c8a9a5SSteve French 	OPEN_PSX_RSP *psx_rsp;
88538c8a9a5SSteve French 
88638c8a9a5SSteve French 	cifs_dbg(FYI, "In POSIX Create\n");
88738c8a9a5SSteve French PsxCreat:
88838c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
88938c8a9a5SSteve French 		      (void **) &pSMBr);
89038c8a9a5SSteve French 	if (rc)
89138c8a9a5SSteve French 		return rc;
89238c8a9a5SSteve French 
89338c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
89438c8a9a5SSteve French 		name_len =
89538c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
89638c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
89738c8a9a5SSteve French 		name_len++;	/* trailing null */
89838c8a9a5SSteve French 		name_len *= 2;
89938c8a9a5SSteve French 	} else {
90038c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, name);
90138c8a9a5SSteve French 	}
90238c8a9a5SSteve French 
90338c8a9a5SSteve French 	params = 6 + name_len;
90438c8a9a5SSteve French 	count = sizeof(OPEN_PSX_REQ);
90538c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
90638c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);	/* large enough */
90738c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
90838c8a9a5SSteve French 	pSMB->Reserved = 0;
90938c8a9a5SSteve French 	pSMB->Flags = 0;
91038c8a9a5SSteve French 	pSMB->Timeout = 0;
91138c8a9a5SSteve French 	pSMB->Reserved2 = 0;
91238c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
91338c8a9a5SSteve French 				InformationLevel) - 4;
91438c8a9a5SSteve French 	offset = param_offset + params;
91538c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
91638c8a9a5SSteve French 	pdata = (OPEN_PSX_REQ *)((char *)(pSMB) + offset + 4);
91738c8a9a5SSteve French 	pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
91838c8a9a5SSteve French 	pdata->Permissions = cpu_to_le64(mode);
91938c8a9a5SSteve French 	pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
92038c8a9a5SSteve French 	pdata->OpenFlags =  cpu_to_le32(*pOplock);
92138c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
92238c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
92338c8a9a5SSteve French 	pSMB->SetupCount = 1;
92438c8a9a5SSteve French 	pSMB->Reserved3 = 0;
92538c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
92638c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
92738c8a9a5SSteve French 
92838c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
92938c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
93038c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
93138c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
93238c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
93338c8a9a5SSteve French 	pSMB->Reserved4 = 0;
93438c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
93538c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
93638c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
93738c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
93838c8a9a5SSteve French 	if (rc) {
93938c8a9a5SSteve French 		cifs_dbg(FYI, "Posix create returned %d\n", rc);
94038c8a9a5SSteve French 		goto psx_create_err;
94138c8a9a5SSteve French 	}
94238c8a9a5SSteve French 
94338c8a9a5SSteve French 	cifs_dbg(FYI, "copying inode info\n");
94438c8a9a5SSteve French 	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
94538c8a9a5SSteve French 
94638c8a9a5SSteve French 	if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
94738c8a9a5SSteve French 		rc = -EIO;	/* bad smb */
94838c8a9a5SSteve French 		goto psx_create_err;
94938c8a9a5SSteve French 	}
95038c8a9a5SSteve French 
95138c8a9a5SSteve French 	/* copy return information to pRetData */
95238c8a9a5SSteve French 	psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
95338c8a9a5SSteve French 			+ le16_to_cpu(pSMBr->t2.DataOffset));
95438c8a9a5SSteve French 
95538c8a9a5SSteve French 	*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
95638c8a9a5SSteve French 	if (netfid)
95738c8a9a5SSteve French 		*netfid = psx_rsp->Fid;   /* cifs fid stays in le */
95838c8a9a5SSteve French 	/* Let caller know file was created so we can set the mode. */
95938c8a9a5SSteve French 	/* Do we care about the CreateAction in any other cases? */
96038c8a9a5SSteve French 	if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
96138c8a9a5SSteve French 		*pOplock |= CIFS_CREATE_ACTION;
96238c8a9a5SSteve French 	/* check to make sure response data is there */
96338c8a9a5SSteve French 	if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
96438c8a9a5SSteve French 		pRetData->Type = cpu_to_le32(-1); /* unknown */
96538c8a9a5SSteve French 		cifs_dbg(NOISY, "unknown type\n");
96638c8a9a5SSteve French 	} else {
96738c8a9a5SSteve French 		if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
96838c8a9a5SSteve French 					+ sizeof(FILE_UNIX_BASIC_INFO)) {
96938c8a9a5SSteve French 			cifs_dbg(VFS, "Open response data too small\n");
97038c8a9a5SSteve French 			pRetData->Type = cpu_to_le32(-1);
97138c8a9a5SSteve French 			goto psx_create_err;
97238c8a9a5SSteve French 		}
97338c8a9a5SSteve French 		memcpy((char *) pRetData,
97438c8a9a5SSteve French 			(char *)psx_rsp + sizeof(OPEN_PSX_RSP),
97538c8a9a5SSteve French 			sizeof(FILE_UNIX_BASIC_INFO));
97638c8a9a5SSteve French 	}
97738c8a9a5SSteve French 
97838c8a9a5SSteve French psx_create_err:
97938c8a9a5SSteve French 	cifs_buf_release(pSMB);
98038c8a9a5SSteve French 
98138c8a9a5SSteve French 	if (posix_flags & SMB_O_DIRECTORY)
98238c8a9a5SSteve French 		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
98338c8a9a5SSteve French 	else
98438c8a9a5SSteve French 		cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
98538c8a9a5SSteve French 
98638c8a9a5SSteve French 	if (rc == -EAGAIN)
98738c8a9a5SSteve French 		goto PsxCreat;
98838c8a9a5SSteve French 
98938c8a9a5SSteve French 	return rc;
99038c8a9a5SSteve French }
99138c8a9a5SSteve French 
convert_disposition(int disposition)99238c8a9a5SSteve French static __u16 convert_disposition(int disposition)
99338c8a9a5SSteve French {
99438c8a9a5SSteve French 	__u16 ofun = 0;
99538c8a9a5SSteve French 
99638c8a9a5SSteve French 	switch (disposition) {
99738c8a9a5SSteve French 		case FILE_SUPERSEDE:
99838c8a9a5SSteve French 			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
99938c8a9a5SSteve French 			break;
100038c8a9a5SSteve French 		case FILE_OPEN:
100138c8a9a5SSteve French 			ofun = SMBOPEN_OAPPEND;
100238c8a9a5SSteve French 			break;
100338c8a9a5SSteve French 		case FILE_CREATE:
100438c8a9a5SSteve French 			ofun = SMBOPEN_OCREATE;
100538c8a9a5SSteve French 			break;
100638c8a9a5SSteve French 		case FILE_OPEN_IF:
100738c8a9a5SSteve French 			ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
100838c8a9a5SSteve French 			break;
100938c8a9a5SSteve French 		case FILE_OVERWRITE:
101038c8a9a5SSteve French 			ofun = SMBOPEN_OTRUNC;
101138c8a9a5SSteve French 			break;
101238c8a9a5SSteve French 		case FILE_OVERWRITE_IF:
101338c8a9a5SSteve French 			ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
101438c8a9a5SSteve French 			break;
101538c8a9a5SSteve French 		default:
101638c8a9a5SSteve French 			cifs_dbg(FYI, "unknown disposition %d\n", disposition);
101738c8a9a5SSteve French 			ofun =  SMBOPEN_OAPPEND; /* regular open */
101838c8a9a5SSteve French 	}
101938c8a9a5SSteve French 	return ofun;
102038c8a9a5SSteve French }
102138c8a9a5SSteve French 
102238c8a9a5SSteve French static int
access_flags_to_smbopen_mode(const int access_flags)102338c8a9a5SSteve French access_flags_to_smbopen_mode(const int access_flags)
102438c8a9a5SSteve French {
102538c8a9a5SSteve French 	int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
102638c8a9a5SSteve French 
102738c8a9a5SSteve French 	if (masked_flags == GENERIC_READ)
102838c8a9a5SSteve French 		return SMBOPEN_READ;
102938c8a9a5SSteve French 	else if (masked_flags == GENERIC_WRITE)
103038c8a9a5SSteve French 		return SMBOPEN_WRITE;
103138c8a9a5SSteve French 
103238c8a9a5SSteve French 	/* just go for read/write */
103338c8a9a5SSteve French 	return SMBOPEN_READWRITE;
103438c8a9a5SSteve French }
103538c8a9a5SSteve French 
103638c8a9a5SSteve French int
SMBLegacyOpen(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const int openDisposition,const int access_flags,const int create_options,__u16 * netfid,int * pOplock,FILE_ALL_INFO * pfile_info,const struct nls_table * nls_codepage,int remap)103738c8a9a5SSteve French SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
103838c8a9a5SSteve French 	    const char *fileName, const int openDisposition,
103938c8a9a5SSteve French 	    const int access_flags, const int create_options, __u16 *netfid,
104038c8a9a5SSteve French 	    int *pOplock, FILE_ALL_INFO *pfile_info,
104138c8a9a5SSteve French 	    const struct nls_table *nls_codepage, int remap)
104238c8a9a5SSteve French {
104338c8a9a5SSteve French 	int rc;
104438c8a9a5SSteve French 	OPENX_REQ *pSMB = NULL;
104538c8a9a5SSteve French 	OPENX_RSP *pSMBr = NULL;
104638c8a9a5SSteve French 	int bytes_returned;
104738c8a9a5SSteve French 	int name_len;
104838c8a9a5SSteve French 	__u16 count;
104938c8a9a5SSteve French 
105038c8a9a5SSteve French OldOpenRetry:
105138c8a9a5SSteve French 	rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
105238c8a9a5SSteve French 		      (void **) &pSMBr);
105338c8a9a5SSteve French 	if (rc)
105438c8a9a5SSteve French 		return rc;
105538c8a9a5SSteve French 
105638c8a9a5SSteve French 	pSMB->AndXCommand = 0xFF;       /* none */
105738c8a9a5SSteve French 
105838c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
105938c8a9a5SSteve French 		count = 1;      /* account for one byte pad to word boundary */
106038c8a9a5SSteve French 		name_len =
106138c8a9a5SSteve French 		   cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
106238c8a9a5SSteve French 				      fileName, PATH_MAX, nls_codepage, remap);
106338c8a9a5SSteve French 		name_len++;     /* trailing null */
106438c8a9a5SSteve French 		name_len *= 2;
106538c8a9a5SSteve French 	} else {
106638c8a9a5SSteve French 		count = 0;      /* no pad */
106738c8a9a5SSteve French 		name_len = copy_path_name(pSMB->fileName, fileName);
106838c8a9a5SSteve French 	}
106938c8a9a5SSteve French 	if (*pOplock & REQ_OPLOCK)
107038c8a9a5SSteve French 		pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
107138c8a9a5SSteve French 	else if (*pOplock & REQ_BATCHOPLOCK)
107238c8a9a5SSteve French 		pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
107338c8a9a5SSteve French 
107438c8a9a5SSteve French 	pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
107538c8a9a5SSteve French 	pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
107638c8a9a5SSteve French 	pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
107738c8a9a5SSteve French 	/* set file as system file if special file such
107838c8a9a5SSteve French 	   as fifo and server expecting SFU style and
107938c8a9a5SSteve French 	   no Unix extensions */
108038c8a9a5SSteve French 
108138c8a9a5SSteve French 	if (create_options & CREATE_OPTION_SPECIAL)
108238c8a9a5SSteve French 		pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
108338c8a9a5SSteve French 	else /* BB FIXME BB */
108438c8a9a5SSteve French 		pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
108538c8a9a5SSteve French 
108638c8a9a5SSteve French 	if (create_options & CREATE_OPTION_READONLY)
108738c8a9a5SSteve French 		pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
108838c8a9a5SSteve French 
108938c8a9a5SSteve French 	/* BB FIXME BB */
109038c8a9a5SSteve French /*	pSMB->CreateOptions = cpu_to_le32(create_options &
109138c8a9a5SSteve French 						 CREATE_OPTIONS_MASK); */
109238c8a9a5SSteve French 	/* BB FIXME END BB */
109338c8a9a5SSteve French 
109438c8a9a5SSteve French 	pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
109538c8a9a5SSteve French 	pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
109638c8a9a5SSteve French 	count += name_len;
109738c8a9a5SSteve French 	inc_rfc1001_len(pSMB, count);
109838c8a9a5SSteve French 
109938c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(count);
110038c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
110138c8a9a5SSteve French 			(struct smb_hdr *)pSMBr, &bytes_returned, 0);
110238c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
110338c8a9a5SSteve French 	if (rc) {
110438c8a9a5SSteve French 		cifs_dbg(FYI, "Error in Open = %d\n", rc);
110538c8a9a5SSteve French 	} else {
110638c8a9a5SSteve French 	/* BB verify if wct == 15 */
110738c8a9a5SSteve French 
110838c8a9a5SSteve French /*		*pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
110938c8a9a5SSteve French 
111038c8a9a5SSteve French 		*netfid = pSMBr->Fid;   /* cifs fid stays in le */
111138c8a9a5SSteve French 		/* Let caller know file was created so we can set the mode. */
111238c8a9a5SSteve French 		/* Do we care about the CreateAction in any other cases? */
111338c8a9a5SSteve French 	/* BB FIXME BB */
111438c8a9a5SSteve French /*		if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
111538c8a9a5SSteve French 			*pOplock |= CIFS_CREATE_ACTION; */
111638c8a9a5SSteve French 	/* BB FIXME END */
111738c8a9a5SSteve French 
111838c8a9a5SSteve French 		if (pfile_info) {
111938c8a9a5SSteve French 			pfile_info->CreationTime = 0; /* BB convert CreateTime*/
112038c8a9a5SSteve French 			pfile_info->LastAccessTime = 0; /* BB fixme */
112138c8a9a5SSteve French 			pfile_info->LastWriteTime = 0; /* BB fixme */
112238c8a9a5SSteve French 			pfile_info->ChangeTime = 0;  /* BB fixme */
112338c8a9a5SSteve French 			pfile_info->Attributes =
112438c8a9a5SSteve French 				cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
112538c8a9a5SSteve French 			/* the file_info buf is endian converted by caller */
112638c8a9a5SSteve French 			pfile_info->AllocationSize =
112738c8a9a5SSteve French 				cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
112838c8a9a5SSteve French 			pfile_info->EndOfFile = pfile_info->AllocationSize;
112938c8a9a5SSteve French 			pfile_info->NumberOfLinks = cpu_to_le32(1);
113038c8a9a5SSteve French 			pfile_info->DeletePending = 0;
113138c8a9a5SSteve French 		}
113238c8a9a5SSteve French 	}
113338c8a9a5SSteve French 
113438c8a9a5SSteve French 	cifs_buf_release(pSMB);
113538c8a9a5SSteve French 	if (rc == -EAGAIN)
113638c8a9a5SSteve French 		goto OldOpenRetry;
113738c8a9a5SSteve French 	return rc;
113838c8a9a5SSteve French }
113938c8a9a5SSteve French 
114038c8a9a5SSteve French int
CIFS_open(const unsigned int xid,struct cifs_open_parms * oparms,int * oplock,FILE_ALL_INFO * buf)114138c8a9a5SSteve French CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
114238c8a9a5SSteve French 	  FILE_ALL_INFO *buf)
114338c8a9a5SSteve French {
114438c8a9a5SSteve French 	int rc;
114538c8a9a5SSteve French 	OPEN_REQ *req = NULL;
114638c8a9a5SSteve French 	OPEN_RSP *rsp = NULL;
114738c8a9a5SSteve French 	int bytes_returned;
114838c8a9a5SSteve French 	int name_len;
114938c8a9a5SSteve French 	__u16 count;
115038c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
115138c8a9a5SSteve French 	struct cifs_tcon *tcon = oparms->tcon;
115238c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
115338c8a9a5SSteve French 	const struct nls_table *nls = cifs_sb->local_nls;
115438c8a9a5SSteve French 	int create_options = oparms->create_options;
115538c8a9a5SSteve French 	int desired_access = oparms->desired_access;
115638c8a9a5SSteve French 	int disposition = oparms->disposition;
115738c8a9a5SSteve French 	const char *path = oparms->path;
115838c8a9a5SSteve French 
115938c8a9a5SSteve French openRetry:
116038c8a9a5SSteve French 	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
116138c8a9a5SSteve French 		      (void **)&rsp);
116238c8a9a5SSteve French 	if (rc)
116338c8a9a5SSteve French 		return rc;
116438c8a9a5SSteve French 
116538c8a9a5SSteve French 	/* no commands go after this */
116638c8a9a5SSteve French 	req->AndXCommand = 0xFF;
116738c8a9a5SSteve French 
116838c8a9a5SSteve French 	if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
116938c8a9a5SSteve French 		/* account for one byte pad to word boundary */
117038c8a9a5SSteve French 		count = 1;
117138c8a9a5SSteve French 		name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
117238c8a9a5SSteve French 					      path, PATH_MAX, nls, remap);
117338c8a9a5SSteve French 		/* trailing null */
117438c8a9a5SSteve French 		name_len++;
117538c8a9a5SSteve French 		name_len *= 2;
117638c8a9a5SSteve French 		req->NameLength = cpu_to_le16(name_len);
117738c8a9a5SSteve French 	} else {
117838c8a9a5SSteve French 		/* BB improve check for buffer overruns BB */
117938c8a9a5SSteve French 		/* no pad */
118038c8a9a5SSteve French 		count = 0;
118138c8a9a5SSteve French 		name_len = copy_path_name(req->fileName, path);
118238c8a9a5SSteve French 		req->NameLength = cpu_to_le16(name_len);
118338c8a9a5SSteve French 	}
118438c8a9a5SSteve French 
118538c8a9a5SSteve French 	if (*oplock & REQ_OPLOCK)
118638c8a9a5SSteve French 		req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
118738c8a9a5SSteve French 	else if (*oplock & REQ_BATCHOPLOCK)
118838c8a9a5SSteve French 		req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
118938c8a9a5SSteve French 
119038c8a9a5SSteve French 	req->DesiredAccess = cpu_to_le32(desired_access);
119138c8a9a5SSteve French 	req->AllocationSize = 0;
119238c8a9a5SSteve French 
119338c8a9a5SSteve French 	/*
119438c8a9a5SSteve French 	 * Set file as system file if special file such as fifo and server
119538c8a9a5SSteve French 	 * expecting SFU style and no Unix extensions.
119638c8a9a5SSteve French 	 */
119738c8a9a5SSteve French 	if (create_options & CREATE_OPTION_SPECIAL)
119838c8a9a5SSteve French 		req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
119938c8a9a5SSteve French 	else
120038c8a9a5SSteve French 		req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
120138c8a9a5SSteve French 
120238c8a9a5SSteve French 	/*
120338c8a9a5SSteve French 	 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
120438c8a9a5SSteve French 	 * sensitive checks for other servers such as Samba.
120538c8a9a5SSteve French 	 */
120638c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_UNIX)
120738c8a9a5SSteve French 		req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
120838c8a9a5SSteve French 
120938c8a9a5SSteve French 	if (create_options & CREATE_OPTION_READONLY)
121038c8a9a5SSteve French 		req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
121138c8a9a5SSteve French 
121238c8a9a5SSteve French 	req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
121338c8a9a5SSteve French 	req->CreateDisposition = cpu_to_le32(disposition);
121438c8a9a5SSteve French 	req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
121538c8a9a5SSteve French 
121638c8a9a5SSteve French 	/* BB Expirement with various impersonation levels and verify */
121738c8a9a5SSteve French 	req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
121838c8a9a5SSteve French 	req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
121938c8a9a5SSteve French 
122038c8a9a5SSteve French 	count += name_len;
122138c8a9a5SSteve French 	inc_rfc1001_len(req, count);
122238c8a9a5SSteve French 
122338c8a9a5SSteve French 	req->ByteCount = cpu_to_le16(count);
122438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
122538c8a9a5SSteve French 			 (struct smb_hdr *)rsp, &bytes_returned, 0);
122638c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
122738c8a9a5SSteve French 	if (rc) {
122838c8a9a5SSteve French 		cifs_dbg(FYI, "Error in Open = %d\n", rc);
122938c8a9a5SSteve French 		cifs_buf_release(req);
123038c8a9a5SSteve French 		if (rc == -EAGAIN)
123138c8a9a5SSteve French 			goto openRetry;
123238c8a9a5SSteve French 		return rc;
123338c8a9a5SSteve French 	}
123438c8a9a5SSteve French 
123538c8a9a5SSteve French 	/* 1 byte no need to le_to_cpu */
123638c8a9a5SSteve French 	*oplock = rsp->OplockLevel;
123738c8a9a5SSteve French 	/* cifs fid stays in le */
123838c8a9a5SSteve French 	oparms->fid->netfid = rsp->Fid;
123938c8a9a5SSteve French 	oparms->fid->access = desired_access;
124038c8a9a5SSteve French 
124138c8a9a5SSteve French 	/* Let caller know file was created so we can set the mode. */
124238c8a9a5SSteve French 	/* Do we care about the CreateAction in any other cases? */
124338c8a9a5SSteve French 	if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
124438c8a9a5SSteve French 		*oplock |= CIFS_CREATE_ACTION;
124538c8a9a5SSteve French 
124638c8a9a5SSteve French 	if (buf) {
12475ca51814SDmitry Antipov 		/* copy commonly used attributes */
12485ca51814SDmitry Antipov 		memcpy(&buf->common_attributes,
12495ca51814SDmitry Antipov 		       &rsp->common_attributes,
12505ca51814SDmitry Antipov 		       sizeof(buf->common_attributes));
125138c8a9a5SSteve French 		/* the file_info buf is endian converted by caller */
125238c8a9a5SSteve French 		buf->AllocationSize = rsp->AllocationSize;
125338c8a9a5SSteve French 		buf->EndOfFile = rsp->EndOfFile;
125438c8a9a5SSteve French 		buf->NumberOfLinks = cpu_to_le32(1);
125538c8a9a5SSteve French 		buf->DeletePending = 0;
125638c8a9a5SSteve French 	}
125738c8a9a5SSteve French 
125838c8a9a5SSteve French 	cifs_buf_release(req);
125938c8a9a5SSteve French 	return rc;
126038c8a9a5SSteve French }
126138c8a9a5SSteve French 
126238c8a9a5SSteve French static void
cifs_readv_callback(struct mid_q_entry * mid)126338c8a9a5SSteve French cifs_readv_callback(struct mid_q_entry *mid)
126438c8a9a5SSteve French {
126538c8a9a5SSteve French 	struct cifs_readdata *rdata = mid->callback_data;
126638c8a9a5SSteve French 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
126738c8a9a5SSteve French 	struct TCP_Server_Info *server = tcon->ses->server;
126838c8a9a5SSteve French 	struct smb_rqst rqst = { .rq_iov = rdata->iov,
126938c8a9a5SSteve French 				 .rq_nvec = 2,
127038c8a9a5SSteve French 				 .rq_iter_size = iov_iter_count(&rdata->iter),
127138c8a9a5SSteve French 				 .rq_iter = rdata->iter };
127238c8a9a5SSteve French 	struct cifs_credits credits = { .value = 1, .instance = 0 };
127338c8a9a5SSteve French 
127438c8a9a5SSteve French 	cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
127538c8a9a5SSteve French 		 __func__, mid->mid, mid->mid_state, rdata->result,
127638c8a9a5SSteve French 		 rdata->bytes);
127738c8a9a5SSteve French 
127838c8a9a5SSteve French 	switch (mid->mid_state) {
127938c8a9a5SSteve French 	case MID_RESPONSE_RECEIVED:
128038c8a9a5SSteve French 		/* result already set, check signature */
128138c8a9a5SSteve French 		if (server->sign) {
128238c8a9a5SSteve French 			int rc = 0;
128338c8a9a5SSteve French 
128438c8a9a5SSteve French 			rc = cifs_verify_signature(&rqst, server,
128538c8a9a5SSteve French 						  mid->sequence_number);
128638c8a9a5SSteve French 			if (rc)
128738c8a9a5SSteve French 				cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
128838c8a9a5SSteve French 					 rc);
128938c8a9a5SSteve French 		}
129038c8a9a5SSteve French 		/* FIXME: should this be counted toward the initiating task? */
129138c8a9a5SSteve French 		task_io_account_read(rdata->got_bytes);
129238c8a9a5SSteve French 		cifs_stats_bytes_read(tcon, rdata->got_bytes);
129338c8a9a5SSteve French 		break;
129438c8a9a5SSteve French 	case MID_REQUEST_SUBMITTED:
129538c8a9a5SSteve French 	case MID_RETRY_NEEDED:
129638c8a9a5SSteve French 		rdata->result = -EAGAIN;
129738c8a9a5SSteve French 		if (server->sign && rdata->got_bytes)
129838c8a9a5SSteve French 			/* reset bytes number since we can not check a sign */
129938c8a9a5SSteve French 			rdata->got_bytes = 0;
130038c8a9a5SSteve French 		/* FIXME: should this be counted toward the initiating task? */
130138c8a9a5SSteve French 		task_io_account_read(rdata->got_bytes);
130238c8a9a5SSteve French 		cifs_stats_bytes_read(tcon, rdata->got_bytes);
130338c8a9a5SSteve French 		break;
130438c8a9a5SSteve French 	default:
130538c8a9a5SSteve French 		rdata->result = -EIO;
130638c8a9a5SSteve French 	}
130738c8a9a5SSteve French 
130838c8a9a5SSteve French 	queue_work(cifsiod_wq, &rdata->work);
130938c8a9a5SSteve French 	release_mid(mid);
131038c8a9a5SSteve French 	add_credits(server, &credits, 0);
131138c8a9a5SSteve French }
131238c8a9a5SSteve French 
131338c8a9a5SSteve French /* cifs_async_readv - send an async write, and set up mid to handle result */
131438c8a9a5SSteve French int
cifs_async_readv(struct cifs_readdata * rdata)131538c8a9a5SSteve French cifs_async_readv(struct cifs_readdata *rdata)
131638c8a9a5SSteve French {
131738c8a9a5SSteve French 	int rc;
131838c8a9a5SSteve French 	READ_REQ *smb = NULL;
131938c8a9a5SSteve French 	int wct;
132038c8a9a5SSteve French 	struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
132138c8a9a5SSteve French 	struct smb_rqst rqst = { .rq_iov = rdata->iov,
132238c8a9a5SSteve French 				 .rq_nvec = 2 };
132338c8a9a5SSteve French 
132438c8a9a5SSteve French 	cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
132538c8a9a5SSteve French 		 __func__, rdata->offset, rdata->bytes);
132638c8a9a5SSteve French 
132738c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_LARGE_FILES)
132838c8a9a5SSteve French 		wct = 12;
132938c8a9a5SSteve French 	else {
133038c8a9a5SSteve French 		wct = 10; /* old style read */
133138c8a9a5SSteve French 		if ((rdata->offset >> 32) > 0)  {
133238c8a9a5SSteve French 			/* can not handle this big offset for old */
133338c8a9a5SSteve French 			return -EIO;
133438c8a9a5SSteve French 		}
133538c8a9a5SSteve French 	}
133638c8a9a5SSteve French 
133738c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
133838c8a9a5SSteve French 	if (rc)
133938c8a9a5SSteve French 		return rc;
134038c8a9a5SSteve French 
134138c8a9a5SSteve French 	smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
134238c8a9a5SSteve French 	smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
134338c8a9a5SSteve French 
134438c8a9a5SSteve French 	smb->AndXCommand = 0xFF;	/* none */
134538c8a9a5SSteve French 	smb->Fid = rdata->cfile->fid.netfid;
134638c8a9a5SSteve French 	smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
134738c8a9a5SSteve French 	if (wct == 12)
134838c8a9a5SSteve French 		smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
134938c8a9a5SSteve French 	smb->Remaining = 0;
135038c8a9a5SSteve French 	smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
135138c8a9a5SSteve French 	smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
135238c8a9a5SSteve French 	if (wct == 12)
135338c8a9a5SSteve French 		smb->ByteCount = 0;
135438c8a9a5SSteve French 	else {
135538c8a9a5SSteve French 		/* old style read */
135638c8a9a5SSteve French 		struct smb_com_readx_req *smbr =
135738c8a9a5SSteve French 			(struct smb_com_readx_req *)smb;
135838c8a9a5SSteve French 		smbr->ByteCount = 0;
135938c8a9a5SSteve French 	}
136038c8a9a5SSteve French 
136138c8a9a5SSteve French 	/* 4 for RFC1001 length + 1 for BCC */
136238c8a9a5SSteve French 	rdata->iov[0].iov_base = smb;
136338c8a9a5SSteve French 	rdata->iov[0].iov_len = 4;
136438c8a9a5SSteve French 	rdata->iov[1].iov_base = (char *)smb + 4;
136538c8a9a5SSteve French 	rdata->iov[1].iov_len = get_rfc1002_length(smb);
136638c8a9a5SSteve French 
136738c8a9a5SSteve French 	kref_get(&rdata->refcount);
136838c8a9a5SSteve French 	rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
136938c8a9a5SSteve French 			     cifs_readv_callback, NULL, rdata, 0, NULL);
137038c8a9a5SSteve French 
137138c8a9a5SSteve French 	if (rc == 0)
137238c8a9a5SSteve French 		cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
137338c8a9a5SSteve French 	else
137438c8a9a5SSteve French 		kref_put(&rdata->refcount, cifs_readdata_release);
137538c8a9a5SSteve French 
137638c8a9a5SSteve French 	cifs_small_buf_release(smb);
137738c8a9a5SSteve French 	return rc;
137838c8a9a5SSteve French }
137938c8a9a5SSteve French 
138038c8a9a5SSteve French int
CIFSSMBRead(const unsigned int xid,struct cifs_io_parms * io_parms,unsigned int * nbytes,char ** buf,int * pbuf_type)138138c8a9a5SSteve French CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
138238c8a9a5SSteve French 	    unsigned int *nbytes, char **buf, int *pbuf_type)
138338c8a9a5SSteve French {
138438c8a9a5SSteve French 	int rc = -EACCES;
138538c8a9a5SSteve French 	READ_REQ *pSMB = NULL;
138638c8a9a5SSteve French 	READ_RSP *pSMBr = NULL;
138738c8a9a5SSteve French 	char *pReadData = NULL;
138838c8a9a5SSteve French 	int wct;
138938c8a9a5SSteve French 	int resp_buf_type = 0;
139038c8a9a5SSteve French 	struct kvec iov[1];
139138c8a9a5SSteve French 	struct kvec rsp_iov;
139238c8a9a5SSteve French 	__u32 pid = io_parms->pid;
139338c8a9a5SSteve French 	__u16 netfid = io_parms->netfid;
139438c8a9a5SSteve French 	__u64 offset = io_parms->offset;
139538c8a9a5SSteve French 	struct cifs_tcon *tcon = io_parms->tcon;
139638c8a9a5SSteve French 	unsigned int count = io_parms->length;
139738c8a9a5SSteve French 
139838c8a9a5SSteve French 	cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
139938c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_LARGE_FILES)
140038c8a9a5SSteve French 		wct = 12;
140138c8a9a5SSteve French 	else {
140238c8a9a5SSteve French 		wct = 10; /* old style read */
140338c8a9a5SSteve French 		if ((offset >> 32) > 0)  {
140438c8a9a5SSteve French 			/* can not handle this big offset for old */
140538c8a9a5SSteve French 			return -EIO;
140638c8a9a5SSteve French 		}
140738c8a9a5SSteve French 	}
140838c8a9a5SSteve French 
140938c8a9a5SSteve French 	*nbytes = 0;
141038c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
141138c8a9a5SSteve French 	if (rc)
141238c8a9a5SSteve French 		return rc;
141338c8a9a5SSteve French 
141438c8a9a5SSteve French 	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
141538c8a9a5SSteve French 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
141638c8a9a5SSteve French 
141738c8a9a5SSteve French 	/* tcon and ses pointer are checked in smb_init */
141838c8a9a5SSteve French 	if (tcon->ses->server == NULL)
141938c8a9a5SSteve French 		return -ECONNABORTED;
142038c8a9a5SSteve French 
142138c8a9a5SSteve French 	pSMB->AndXCommand = 0xFF;       /* none */
142238c8a9a5SSteve French 	pSMB->Fid = netfid;
142338c8a9a5SSteve French 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
142438c8a9a5SSteve French 	if (wct == 12)
142538c8a9a5SSteve French 		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
142638c8a9a5SSteve French 
142738c8a9a5SSteve French 	pSMB->Remaining = 0;
142838c8a9a5SSteve French 	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
142938c8a9a5SSteve French 	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
143038c8a9a5SSteve French 	if (wct == 12)
143138c8a9a5SSteve French 		pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
143238c8a9a5SSteve French 	else {
143338c8a9a5SSteve French 		/* old style read */
143438c8a9a5SSteve French 		struct smb_com_readx_req *pSMBW =
143538c8a9a5SSteve French 			(struct smb_com_readx_req *)pSMB;
143638c8a9a5SSteve French 		pSMBW->ByteCount = 0;
143738c8a9a5SSteve French 	}
143838c8a9a5SSteve French 
143938c8a9a5SSteve French 	iov[0].iov_base = (char *)pSMB;
144038c8a9a5SSteve French 	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
144138c8a9a5SSteve French 	rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
144238c8a9a5SSteve French 			  CIFS_LOG_ERROR, &rsp_iov);
144338c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
144438c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
144538c8a9a5SSteve French 	pSMBr = (READ_RSP *)rsp_iov.iov_base;
144638c8a9a5SSteve French 	if (rc) {
144738c8a9a5SSteve French 		cifs_dbg(VFS, "Send error in read = %d\n", rc);
144838c8a9a5SSteve French 	} else {
144938c8a9a5SSteve French 		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
145038c8a9a5SSteve French 		data_length = data_length << 16;
145138c8a9a5SSteve French 		data_length += le16_to_cpu(pSMBr->DataLength);
145238c8a9a5SSteve French 		*nbytes = data_length;
145338c8a9a5SSteve French 
145438c8a9a5SSteve French 		/*check that DataLength would not go beyond end of SMB */
145538c8a9a5SSteve French 		if ((data_length > CIFSMaxBufSize)
145638c8a9a5SSteve French 				|| (data_length > count)) {
145738c8a9a5SSteve French 			cifs_dbg(FYI, "bad length %d for count %d\n",
145838c8a9a5SSteve French 				 data_length, count);
145938c8a9a5SSteve French 			rc = -EIO;
146038c8a9a5SSteve French 			*nbytes = 0;
146138c8a9a5SSteve French 		} else {
146238c8a9a5SSteve French 			pReadData = (char *) (&pSMBr->hdr.Protocol) +
146338c8a9a5SSteve French 					le16_to_cpu(pSMBr->DataOffset);
146438c8a9a5SSteve French /*			if (rc = copy_to_user(buf, pReadData, data_length)) {
146538c8a9a5SSteve French 				cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
146638c8a9a5SSteve French 				rc = -EFAULT;
146738c8a9a5SSteve French 			}*/ /* can not use copy_to_user when using page cache*/
146838c8a9a5SSteve French 			if (*buf)
146938c8a9a5SSteve French 				memcpy(*buf, pReadData, data_length);
147038c8a9a5SSteve French 		}
147138c8a9a5SSteve French 	}
147238c8a9a5SSteve French 
147338c8a9a5SSteve French 	if (*buf) {
147438c8a9a5SSteve French 		free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
147538c8a9a5SSteve French 	} else if (resp_buf_type != CIFS_NO_BUFFER) {
147638c8a9a5SSteve French 		/* return buffer to caller to free */
147738c8a9a5SSteve French 		*buf = rsp_iov.iov_base;
147838c8a9a5SSteve French 		if (resp_buf_type == CIFS_SMALL_BUFFER)
147938c8a9a5SSteve French 			*pbuf_type = CIFS_SMALL_BUFFER;
148038c8a9a5SSteve French 		else if (resp_buf_type == CIFS_LARGE_BUFFER)
148138c8a9a5SSteve French 			*pbuf_type = CIFS_LARGE_BUFFER;
148238c8a9a5SSteve French 	} /* else no valid buffer on return - leave as null */
148338c8a9a5SSteve French 
148438c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
148538c8a9a5SSteve French 		since file handle passed in no longer valid */
148638c8a9a5SSteve French 	return rc;
148738c8a9a5SSteve French }
148838c8a9a5SSteve French 
148938c8a9a5SSteve French 
149038c8a9a5SSteve French int
CIFSSMBWrite(const unsigned int xid,struct cifs_io_parms * io_parms,unsigned int * nbytes,const char * buf)149138c8a9a5SSteve French CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
149238c8a9a5SSteve French 	     unsigned int *nbytes, const char *buf)
149338c8a9a5SSteve French {
149438c8a9a5SSteve French 	int rc = -EACCES;
149538c8a9a5SSteve French 	WRITE_REQ *pSMB = NULL;
149638c8a9a5SSteve French 	WRITE_RSP *pSMBr = NULL;
149738c8a9a5SSteve French 	int bytes_returned, wct;
149838c8a9a5SSteve French 	__u32 bytes_sent;
149938c8a9a5SSteve French 	__u16 byte_count;
150038c8a9a5SSteve French 	__u32 pid = io_parms->pid;
150138c8a9a5SSteve French 	__u16 netfid = io_parms->netfid;
150238c8a9a5SSteve French 	__u64 offset = io_parms->offset;
150338c8a9a5SSteve French 	struct cifs_tcon *tcon = io_parms->tcon;
150438c8a9a5SSteve French 	unsigned int count = io_parms->length;
150538c8a9a5SSteve French 
150638c8a9a5SSteve French 	*nbytes = 0;
150738c8a9a5SSteve French 
150838c8a9a5SSteve French 	/* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
150938c8a9a5SSteve French 	if (tcon->ses == NULL)
151038c8a9a5SSteve French 		return -ECONNABORTED;
151138c8a9a5SSteve French 
151238c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_LARGE_FILES)
151338c8a9a5SSteve French 		wct = 14;
151438c8a9a5SSteve French 	else {
151538c8a9a5SSteve French 		wct = 12;
151638c8a9a5SSteve French 		if ((offset >> 32) > 0) {
151738c8a9a5SSteve French 			/* can not handle big offset for old srv */
151838c8a9a5SSteve French 			return -EIO;
151938c8a9a5SSteve French 		}
152038c8a9a5SSteve French 	}
152138c8a9a5SSteve French 
152238c8a9a5SSteve French 	rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
152338c8a9a5SSteve French 		      (void **) &pSMBr);
152438c8a9a5SSteve French 	if (rc)
152538c8a9a5SSteve French 		return rc;
152638c8a9a5SSteve French 
152738c8a9a5SSteve French 	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
152838c8a9a5SSteve French 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
152938c8a9a5SSteve French 
153038c8a9a5SSteve French 	/* tcon and ses pointer are checked in smb_init */
153138c8a9a5SSteve French 	if (tcon->ses->server == NULL)
153238c8a9a5SSteve French 		return -ECONNABORTED;
153338c8a9a5SSteve French 
153438c8a9a5SSteve French 	pSMB->AndXCommand = 0xFF;	/* none */
153538c8a9a5SSteve French 	pSMB->Fid = netfid;
153638c8a9a5SSteve French 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
153738c8a9a5SSteve French 	if (wct == 14)
153838c8a9a5SSteve French 		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
153938c8a9a5SSteve French 
154038c8a9a5SSteve French 	pSMB->Reserved = 0xFFFFFFFF;
154138c8a9a5SSteve French 	pSMB->WriteMode = 0;
154238c8a9a5SSteve French 	pSMB->Remaining = 0;
154338c8a9a5SSteve French 
154438c8a9a5SSteve French 	/* Can increase buffer size if buffer is big enough in some cases ie we
154538c8a9a5SSteve French 	can send more if LARGE_WRITE_X capability returned by the server and if
154638c8a9a5SSteve French 	our buffer is big enough or if we convert to iovecs on socket writes
154738c8a9a5SSteve French 	and eliminate the copy to the CIFS buffer */
154838c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
154938c8a9a5SSteve French 		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
155038c8a9a5SSteve French 	} else {
155138c8a9a5SSteve French 		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
155238c8a9a5SSteve French 			 & ~0xFF;
155338c8a9a5SSteve French 	}
155438c8a9a5SSteve French 
155538c8a9a5SSteve French 	if (bytes_sent > count)
155638c8a9a5SSteve French 		bytes_sent = count;
155738c8a9a5SSteve French 	pSMB->DataOffset =
155838c8a9a5SSteve French 		cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
155938c8a9a5SSteve French 	if (buf)
156038c8a9a5SSteve French 		memcpy(pSMB->Data, buf, bytes_sent);
156138c8a9a5SSteve French 	else if (count != 0) {
156238c8a9a5SSteve French 		/* No buffer */
156338c8a9a5SSteve French 		cifs_buf_release(pSMB);
156438c8a9a5SSteve French 		return -EINVAL;
156538c8a9a5SSteve French 	} /* else setting file size with write of zero bytes */
156638c8a9a5SSteve French 	if (wct == 14)
156738c8a9a5SSteve French 		byte_count = bytes_sent + 1; /* pad */
156838c8a9a5SSteve French 	else /* wct == 12 */
156938c8a9a5SSteve French 		byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
157038c8a9a5SSteve French 
157138c8a9a5SSteve French 	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
157238c8a9a5SSteve French 	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
157338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
157438c8a9a5SSteve French 
157538c8a9a5SSteve French 	if (wct == 14)
157638c8a9a5SSteve French 		pSMB->ByteCount = cpu_to_le16(byte_count);
157738c8a9a5SSteve French 	else { /* old style write has byte count 4 bytes earlier
157838c8a9a5SSteve French 		  so 4 bytes pad  */
157938c8a9a5SSteve French 		struct smb_com_writex_req *pSMBW =
158038c8a9a5SSteve French 			(struct smb_com_writex_req *)pSMB;
158138c8a9a5SSteve French 		pSMBW->ByteCount = cpu_to_le16(byte_count);
158238c8a9a5SSteve French 	}
158338c8a9a5SSteve French 
158438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
158538c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
158638c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
158738c8a9a5SSteve French 	if (rc) {
158838c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in write = %d\n", rc);
158938c8a9a5SSteve French 	} else {
159038c8a9a5SSteve French 		*nbytes = le16_to_cpu(pSMBr->CountHigh);
159138c8a9a5SSteve French 		*nbytes = (*nbytes) << 16;
159238c8a9a5SSteve French 		*nbytes += le16_to_cpu(pSMBr->Count);
159338c8a9a5SSteve French 
159438c8a9a5SSteve French 		/*
159538c8a9a5SSteve French 		 * Mask off high 16 bits when bytes written as returned by the
159638c8a9a5SSteve French 		 * server is greater than bytes requested by the client. Some
159738c8a9a5SSteve French 		 * OS/2 servers are known to set incorrect CountHigh values.
159838c8a9a5SSteve French 		 */
159938c8a9a5SSteve French 		if (*nbytes > count)
160038c8a9a5SSteve French 			*nbytes &= 0xFFFF;
160138c8a9a5SSteve French 	}
160238c8a9a5SSteve French 
160338c8a9a5SSteve French 	cifs_buf_release(pSMB);
160438c8a9a5SSteve French 
160538c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
160638c8a9a5SSteve French 		since file handle passed in no longer valid */
160738c8a9a5SSteve French 
160838c8a9a5SSteve French 	return rc;
160938c8a9a5SSteve French }
161038c8a9a5SSteve French 
161138c8a9a5SSteve French /*
161238c8a9a5SSteve French  * Check the mid_state and signature on received buffer (if any), and queue the
161338c8a9a5SSteve French  * workqueue completion task.
161438c8a9a5SSteve French  */
161538c8a9a5SSteve French static void
cifs_writev_callback(struct mid_q_entry * mid)161638c8a9a5SSteve French cifs_writev_callback(struct mid_q_entry *mid)
161738c8a9a5SSteve French {
161838c8a9a5SSteve French 	struct cifs_writedata *wdata = mid->callback_data;
161938c8a9a5SSteve French 	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
162038c8a9a5SSteve French 	unsigned int written;
162138c8a9a5SSteve French 	WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
162238c8a9a5SSteve French 	struct cifs_credits credits = { .value = 1, .instance = 0 };
162338c8a9a5SSteve French 
162438c8a9a5SSteve French 	switch (mid->mid_state) {
162538c8a9a5SSteve French 	case MID_RESPONSE_RECEIVED:
162638c8a9a5SSteve French 		wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
162738c8a9a5SSteve French 		if (wdata->result != 0)
162838c8a9a5SSteve French 			break;
162938c8a9a5SSteve French 
163038c8a9a5SSteve French 		written = le16_to_cpu(smb->CountHigh);
163138c8a9a5SSteve French 		written <<= 16;
163238c8a9a5SSteve French 		written += le16_to_cpu(smb->Count);
163338c8a9a5SSteve French 		/*
163438c8a9a5SSteve French 		 * Mask off high 16 bits when bytes written as returned
163538c8a9a5SSteve French 		 * by the server is greater than bytes requested by the
163638c8a9a5SSteve French 		 * client. OS/2 servers are known to set incorrect
163738c8a9a5SSteve French 		 * CountHigh values.
163838c8a9a5SSteve French 		 */
163938c8a9a5SSteve French 		if (written > wdata->bytes)
164038c8a9a5SSteve French 			written &= 0xFFFF;
164138c8a9a5SSteve French 
164238c8a9a5SSteve French 		if (written < wdata->bytes)
164338c8a9a5SSteve French 			wdata->result = -ENOSPC;
164438c8a9a5SSteve French 		else
164538c8a9a5SSteve French 			wdata->bytes = written;
164638c8a9a5SSteve French 		break;
164738c8a9a5SSteve French 	case MID_REQUEST_SUBMITTED:
164838c8a9a5SSteve French 	case MID_RETRY_NEEDED:
164938c8a9a5SSteve French 		wdata->result = -EAGAIN;
165038c8a9a5SSteve French 		break;
165138c8a9a5SSteve French 	default:
165238c8a9a5SSteve French 		wdata->result = -EIO;
165338c8a9a5SSteve French 		break;
165438c8a9a5SSteve French 	}
165538c8a9a5SSteve French 
165638c8a9a5SSteve French 	queue_work(cifsiod_wq, &wdata->work);
165738c8a9a5SSteve French 	release_mid(mid);
165838c8a9a5SSteve French 	add_credits(tcon->ses->server, &credits, 0);
165938c8a9a5SSteve French }
166038c8a9a5SSteve French 
166138c8a9a5SSteve French /* cifs_async_writev - send an async write, and set up mid to handle result */
166238c8a9a5SSteve French int
cifs_async_writev(struct cifs_writedata * wdata,void (* release)(struct kref * kref))166338c8a9a5SSteve French cifs_async_writev(struct cifs_writedata *wdata,
166438c8a9a5SSteve French 		  void (*release)(struct kref *kref))
166538c8a9a5SSteve French {
166638c8a9a5SSteve French 	int rc = -EACCES;
166738c8a9a5SSteve French 	WRITE_REQ *smb = NULL;
166838c8a9a5SSteve French 	int wct;
166938c8a9a5SSteve French 	struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
167038c8a9a5SSteve French 	struct kvec iov[2];
167138c8a9a5SSteve French 	struct smb_rqst rqst = { };
167238c8a9a5SSteve French 
167338c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
167438c8a9a5SSteve French 		wct = 14;
167538c8a9a5SSteve French 	} else {
167638c8a9a5SSteve French 		wct = 12;
167738c8a9a5SSteve French 		if (wdata->offset >> 32 > 0) {
167838c8a9a5SSteve French 			/* can not handle big offset for old srv */
167938c8a9a5SSteve French 			return -EIO;
168038c8a9a5SSteve French 		}
168138c8a9a5SSteve French 	}
168238c8a9a5SSteve French 
168338c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
168438c8a9a5SSteve French 	if (rc)
168538c8a9a5SSteve French 		goto async_writev_out;
168638c8a9a5SSteve French 
168738c8a9a5SSteve French 	smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
168838c8a9a5SSteve French 	smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
168938c8a9a5SSteve French 
169038c8a9a5SSteve French 	smb->AndXCommand = 0xFF;	/* none */
169138c8a9a5SSteve French 	smb->Fid = wdata->cfile->fid.netfid;
169238c8a9a5SSteve French 	smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
169338c8a9a5SSteve French 	if (wct == 14)
169438c8a9a5SSteve French 		smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
169538c8a9a5SSteve French 	smb->Reserved = 0xFFFFFFFF;
169638c8a9a5SSteve French 	smb->WriteMode = 0;
169738c8a9a5SSteve French 	smb->Remaining = 0;
169838c8a9a5SSteve French 
169938c8a9a5SSteve French 	smb->DataOffset =
170038c8a9a5SSteve French 	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
170138c8a9a5SSteve French 
170238c8a9a5SSteve French 	/* 4 for RFC1001 length + 1 for BCC */
170338c8a9a5SSteve French 	iov[0].iov_len = 4;
170438c8a9a5SSteve French 	iov[0].iov_base = smb;
170538c8a9a5SSteve French 	iov[1].iov_len = get_rfc1002_length(smb) + 1;
170638c8a9a5SSteve French 	iov[1].iov_base = (char *)smb + 4;
170738c8a9a5SSteve French 
170838c8a9a5SSteve French 	rqst.rq_iov = iov;
170938c8a9a5SSteve French 	rqst.rq_nvec = 2;
171038c8a9a5SSteve French 	rqst.rq_iter = wdata->iter;
171138c8a9a5SSteve French 	rqst.rq_iter_size = iov_iter_count(&wdata->iter);
171238c8a9a5SSteve French 
171338c8a9a5SSteve French 	cifs_dbg(FYI, "async write at %llu %u bytes\n",
171438c8a9a5SSteve French 		 wdata->offset, wdata->bytes);
171538c8a9a5SSteve French 
171638c8a9a5SSteve French 	smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
171738c8a9a5SSteve French 	smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
171838c8a9a5SSteve French 
171938c8a9a5SSteve French 	if (wct == 14) {
172038c8a9a5SSteve French 		inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
172138c8a9a5SSteve French 		put_bcc(wdata->bytes + 1, &smb->hdr);
172238c8a9a5SSteve French 	} else {
172338c8a9a5SSteve French 		/* wct == 12 */
172438c8a9a5SSteve French 		struct smb_com_writex_req *smbw =
172538c8a9a5SSteve French 				(struct smb_com_writex_req *)smb;
172638c8a9a5SSteve French 		inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
172738c8a9a5SSteve French 		put_bcc(wdata->bytes + 5, &smbw->hdr);
172838c8a9a5SSteve French 		iov[1].iov_len += 4; /* pad bigger by four bytes */
172938c8a9a5SSteve French 	}
173038c8a9a5SSteve French 
173138c8a9a5SSteve French 	kref_get(&wdata->refcount);
173238c8a9a5SSteve French 	rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
173338c8a9a5SSteve French 			     cifs_writev_callback, NULL, wdata, 0, NULL);
173438c8a9a5SSteve French 
173538c8a9a5SSteve French 	if (rc == 0)
173638c8a9a5SSteve French 		cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
173738c8a9a5SSteve French 	else
173838c8a9a5SSteve French 		kref_put(&wdata->refcount, release);
173938c8a9a5SSteve French 
174038c8a9a5SSteve French async_writev_out:
174138c8a9a5SSteve French 	cifs_small_buf_release(smb);
174238c8a9a5SSteve French 	return rc;
174338c8a9a5SSteve French }
174438c8a9a5SSteve French 
174538c8a9a5SSteve French int
CIFSSMBWrite2(const unsigned int xid,struct cifs_io_parms * io_parms,unsigned int * nbytes,struct kvec * iov,int n_vec)174638c8a9a5SSteve French CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
174738c8a9a5SSteve French 	      unsigned int *nbytes, struct kvec *iov, int n_vec)
174838c8a9a5SSteve French {
174938c8a9a5SSteve French 	int rc;
175038c8a9a5SSteve French 	WRITE_REQ *pSMB = NULL;
175138c8a9a5SSteve French 	int wct;
175238c8a9a5SSteve French 	int smb_hdr_len;
175338c8a9a5SSteve French 	int resp_buf_type = 0;
175438c8a9a5SSteve French 	__u32 pid = io_parms->pid;
175538c8a9a5SSteve French 	__u16 netfid = io_parms->netfid;
175638c8a9a5SSteve French 	__u64 offset = io_parms->offset;
175738c8a9a5SSteve French 	struct cifs_tcon *tcon = io_parms->tcon;
175838c8a9a5SSteve French 	unsigned int count = io_parms->length;
175938c8a9a5SSteve French 	struct kvec rsp_iov;
176038c8a9a5SSteve French 
176138c8a9a5SSteve French 	*nbytes = 0;
176238c8a9a5SSteve French 
176338c8a9a5SSteve French 	cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
176438c8a9a5SSteve French 
176538c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_LARGE_FILES) {
176638c8a9a5SSteve French 		wct = 14;
176738c8a9a5SSteve French 	} else {
176838c8a9a5SSteve French 		wct = 12;
176938c8a9a5SSteve French 		if ((offset >> 32) > 0) {
177038c8a9a5SSteve French 			/* can not handle big offset for old srv */
177138c8a9a5SSteve French 			return -EIO;
177238c8a9a5SSteve French 		}
177338c8a9a5SSteve French 	}
177438c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
177538c8a9a5SSteve French 	if (rc)
177638c8a9a5SSteve French 		return rc;
177738c8a9a5SSteve French 
177838c8a9a5SSteve French 	pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
177938c8a9a5SSteve French 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
178038c8a9a5SSteve French 
178138c8a9a5SSteve French 	/* tcon and ses pointer are checked in smb_init */
178238c8a9a5SSteve French 	if (tcon->ses->server == NULL)
178338c8a9a5SSteve French 		return -ECONNABORTED;
178438c8a9a5SSteve French 
178538c8a9a5SSteve French 	pSMB->AndXCommand = 0xFF;	/* none */
178638c8a9a5SSteve French 	pSMB->Fid = netfid;
178738c8a9a5SSteve French 	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
178838c8a9a5SSteve French 	if (wct == 14)
178938c8a9a5SSteve French 		pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
179038c8a9a5SSteve French 	pSMB->Reserved = 0xFFFFFFFF;
179138c8a9a5SSteve French 	pSMB->WriteMode = 0;
179238c8a9a5SSteve French 	pSMB->Remaining = 0;
179338c8a9a5SSteve French 
179438c8a9a5SSteve French 	pSMB->DataOffset =
179538c8a9a5SSteve French 	    cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
179638c8a9a5SSteve French 
179738c8a9a5SSteve French 	pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
179838c8a9a5SSteve French 	pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
179938c8a9a5SSteve French 	/* header + 1 byte pad */
180038c8a9a5SSteve French 	smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
180138c8a9a5SSteve French 	if (wct == 14)
180238c8a9a5SSteve French 		inc_rfc1001_len(pSMB, count + 1);
180338c8a9a5SSteve French 	else /* wct == 12 */
180438c8a9a5SSteve French 		inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
180538c8a9a5SSteve French 	if (wct == 14)
180638c8a9a5SSteve French 		pSMB->ByteCount = cpu_to_le16(count + 1);
180738c8a9a5SSteve French 	else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
180838c8a9a5SSteve French 		struct smb_com_writex_req *pSMBW =
180938c8a9a5SSteve French 				(struct smb_com_writex_req *)pSMB;
181038c8a9a5SSteve French 		pSMBW->ByteCount = cpu_to_le16(count + 5);
181138c8a9a5SSteve French 	}
181238c8a9a5SSteve French 	iov[0].iov_base = pSMB;
181338c8a9a5SSteve French 	if (wct == 14)
181438c8a9a5SSteve French 		iov[0].iov_len = smb_hdr_len + 4;
181538c8a9a5SSteve French 	else /* wct == 12 pad bigger by four bytes */
181638c8a9a5SSteve French 		iov[0].iov_len = smb_hdr_len + 8;
181738c8a9a5SSteve French 
181838c8a9a5SSteve French 	rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
181938c8a9a5SSteve French 			  &rsp_iov);
182038c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
182138c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
182238c8a9a5SSteve French 	if (rc) {
182338c8a9a5SSteve French 		cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
182438c8a9a5SSteve French 	} else if (resp_buf_type == 0) {
182538c8a9a5SSteve French 		/* presumably this can not happen, but best to be safe */
182638c8a9a5SSteve French 		rc = -EIO;
182738c8a9a5SSteve French 	} else {
182838c8a9a5SSteve French 		WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
182938c8a9a5SSteve French 		*nbytes = le16_to_cpu(pSMBr->CountHigh);
183038c8a9a5SSteve French 		*nbytes = (*nbytes) << 16;
183138c8a9a5SSteve French 		*nbytes += le16_to_cpu(pSMBr->Count);
183238c8a9a5SSteve French 
183338c8a9a5SSteve French 		/*
183438c8a9a5SSteve French 		 * Mask off high 16 bits when bytes written as returned by the
183538c8a9a5SSteve French 		 * server is greater than bytes requested by the client. OS/2
183638c8a9a5SSteve French 		 * servers are known to set incorrect CountHigh values.
183738c8a9a5SSteve French 		 */
183838c8a9a5SSteve French 		if (*nbytes > count)
183938c8a9a5SSteve French 			*nbytes &= 0xFFFF;
184038c8a9a5SSteve French 	}
184138c8a9a5SSteve French 
184238c8a9a5SSteve French 	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
184338c8a9a5SSteve French 
184438c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
184538c8a9a5SSteve French 		since file handle passed in no longer valid */
184638c8a9a5SSteve French 
184738c8a9a5SSteve French 	return rc;
184838c8a9a5SSteve French }
184938c8a9a5SSteve French 
cifs_lockv(const unsigned int xid,struct cifs_tcon * tcon,const __u16 netfid,const __u8 lock_type,const __u32 num_unlock,const __u32 num_lock,LOCKING_ANDX_RANGE * buf)185038c8a9a5SSteve French int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
185138c8a9a5SSteve French 	       const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
185238c8a9a5SSteve French 	       const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
185338c8a9a5SSteve French {
185438c8a9a5SSteve French 	int rc = 0;
185538c8a9a5SSteve French 	LOCK_REQ *pSMB = NULL;
185638c8a9a5SSteve French 	struct kvec iov[2];
185738c8a9a5SSteve French 	struct kvec rsp_iov;
185838c8a9a5SSteve French 	int resp_buf_type;
185938c8a9a5SSteve French 	__u16 count;
186038c8a9a5SSteve French 
186138c8a9a5SSteve French 	cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
186238c8a9a5SSteve French 		 num_lock, num_unlock);
186338c8a9a5SSteve French 
186438c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
186538c8a9a5SSteve French 	if (rc)
186638c8a9a5SSteve French 		return rc;
186738c8a9a5SSteve French 
186838c8a9a5SSteve French 	pSMB->Timeout = 0;
186938c8a9a5SSteve French 	pSMB->NumberOfLocks = cpu_to_le16(num_lock);
187038c8a9a5SSteve French 	pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
187138c8a9a5SSteve French 	pSMB->LockType = lock_type;
187238c8a9a5SSteve French 	pSMB->AndXCommand = 0xFF; /* none */
187338c8a9a5SSteve French 	pSMB->Fid = netfid; /* netfid stays le */
187438c8a9a5SSteve French 
187538c8a9a5SSteve French 	count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
187638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, count);
187738c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(count);
187838c8a9a5SSteve French 
187938c8a9a5SSteve French 	iov[0].iov_base = (char *)pSMB;
188038c8a9a5SSteve French 	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
188138c8a9a5SSteve French 			 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
188238c8a9a5SSteve French 	iov[1].iov_base = (char *)buf;
188338c8a9a5SSteve French 	iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
188438c8a9a5SSteve French 
188538c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
188638c8a9a5SSteve French 	rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type,
188738c8a9a5SSteve French 			  CIFS_NO_RSP_BUF, &rsp_iov);
188838c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
188938c8a9a5SSteve French 	if (rc)
189038c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
189138c8a9a5SSteve French 
189238c8a9a5SSteve French 	return rc;
189338c8a9a5SSteve French }
189438c8a9a5SSteve French 
189538c8a9a5SSteve French int
CIFSSMBLock(const unsigned int xid,struct cifs_tcon * tcon,const __u16 smb_file_id,const __u32 netpid,const __u64 len,const __u64 offset,const __u32 numUnlock,const __u32 numLock,const __u8 lockType,const bool waitFlag,const __u8 oplock_level)189638c8a9a5SSteve French CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
189738c8a9a5SSteve French 	    const __u16 smb_file_id, const __u32 netpid, const __u64 len,
189838c8a9a5SSteve French 	    const __u64 offset, const __u32 numUnlock,
189938c8a9a5SSteve French 	    const __u32 numLock, const __u8 lockType,
190038c8a9a5SSteve French 	    const bool waitFlag, const __u8 oplock_level)
190138c8a9a5SSteve French {
190238c8a9a5SSteve French 	int rc = 0;
190338c8a9a5SSteve French 	LOCK_REQ *pSMB = NULL;
190438c8a9a5SSteve French /*	LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
190538c8a9a5SSteve French 	int bytes_returned;
190638c8a9a5SSteve French 	int flags = 0;
190738c8a9a5SSteve French 	__u16 count;
190838c8a9a5SSteve French 
190938c8a9a5SSteve French 	cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
191038c8a9a5SSteve French 		 (int)waitFlag, numLock);
191138c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
191238c8a9a5SSteve French 
191338c8a9a5SSteve French 	if (rc)
191438c8a9a5SSteve French 		return rc;
191538c8a9a5SSteve French 
191638c8a9a5SSteve French 	if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
191738c8a9a5SSteve French 		/* no response expected */
191838c8a9a5SSteve French 		flags = CIFS_NO_SRV_RSP | CIFS_NON_BLOCKING | CIFS_OBREAK_OP;
191938c8a9a5SSteve French 		pSMB->Timeout = 0;
192038c8a9a5SSteve French 	} else if (waitFlag) {
192138c8a9a5SSteve French 		flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
192238c8a9a5SSteve French 		pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
192338c8a9a5SSteve French 	} else {
192438c8a9a5SSteve French 		pSMB->Timeout = 0;
192538c8a9a5SSteve French 	}
192638c8a9a5SSteve French 
192738c8a9a5SSteve French 	pSMB->NumberOfLocks = cpu_to_le16(numLock);
192838c8a9a5SSteve French 	pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
192938c8a9a5SSteve French 	pSMB->LockType = lockType;
193038c8a9a5SSteve French 	pSMB->OplockLevel = oplock_level;
193138c8a9a5SSteve French 	pSMB->AndXCommand = 0xFF;	/* none */
193238c8a9a5SSteve French 	pSMB->Fid = smb_file_id; /* netfid stays le */
193338c8a9a5SSteve French 
193438c8a9a5SSteve French 	if ((numLock != 0) || (numUnlock != 0)) {
193538c8a9a5SSteve French 		pSMB->Locks[0].Pid = cpu_to_le16(netpid);
193638c8a9a5SSteve French 		/* BB where to store pid high? */
193738c8a9a5SSteve French 		pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
193838c8a9a5SSteve French 		pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
193938c8a9a5SSteve French 		pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
194038c8a9a5SSteve French 		pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
194138c8a9a5SSteve French 		count = sizeof(LOCKING_ANDX_RANGE);
194238c8a9a5SSteve French 	} else {
194338c8a9a5SSteve French 		/* oplock break */
194438c8a9a5SSteve French 		count = 0;
194538c8a9a5SSteve French 	}
194638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, count);
194738c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(count);
194838c8a9a5SSteve French 
194938c8a9a5SSteve French 	if (waitFlag)
195038c8a9a5SSteve French 		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
195138c8a9a5SSteve French 			(struct smb_hdr *) pSMB, &bytes_returned);
195238c8a9a5SSteve French 	else
195338c8a9a5SSteve French 		rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
195438c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
195538c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
195638c8a9a5SSteve French 	if (rc)
195738c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
195838c8a9a5SSteve French 
195938c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
196038c8a9a5SSteve French 	since file handle passed in no longer valid */
196138c8a9a5SSteve French 	return rc;
196238c8a9a5SSteve French }
196338c8a9a5SSteve French 
196438c8a9a5SSteve French int
CIFSSMBPosixLock(const unsigned int xid,struct cifs_tcon * tcon,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)196538c8a9a5SSteve French CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
196638c8a9a5SSteve French 		const __u16 smb_file_id, const __u32 netpid,
196738c8a9a5SSteve French 		const loff_t start_offset, const __u64 len,
196838c8a9a5SSteve French 		struct file_lock *pLockData, const __u16 lock_type,
196938c8a9a5SSteve French 		const bool waitFlag)
197038c8a9a5SSteve French {
197138c8a9a5SSteve French 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
197238c8a9a5SSteve French 	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
197338c8a9a5SSteve French 	struct cifs_posix_lock *parm_data;
197438c8a9a5SSteve French 	int rc = 0;
197538c8a9a5SSteve French 	int timeout = 0;
197638c8a9a5SSteve French 	int bytes_returned = 0;
197738c8a9a5SSteve French 	int resp_buf_type = 0;
197838c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count, count;
197938c8a9a5SSteve French 	struct kvec iov[1];
198038c8a9a5SSteve French 	struct kvec rsp_iov;
198138c8a9a5SSteve French 
198238c8a9a5SSteve French 	cifs_dbg(FYI, "Posix Lock\n");
198338c8a9a5SSteve French 
198438c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
198538c8a9a5SSteve French 
198638c8a9a5SSteve French 	if (rc)
198738c8a9a5SSteve French 		return rc;
198838c8a9a5SSteve French 
198938c8a9a5SSteve French 	pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
199038c8a9a5SSteve French 
199138c8a9a5SSteve French 	params = 6;
199238c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
199338c8a9a5SSteve French 	pSMB->Reserved = 0;
199438c8a9a5SSteve French 	pSMB->Flags = 0;
199538c8a9a5SSteve French 	pSMB->Reserved2 = 0;
199638c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
199738c8a9a5SSteve French 	offset = param_offset + params;
199838c8a9a5SSteve French 
199938c8a9a5SSteve French 	count = sizeof(struct cifs_posix_lock);
200038c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
200138c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
200238c8a9a5SSteve French 	pSMB->SetupCount = 1;
200338c8a9a5SSteve French 	pSMB->Reserved3 = 0;
200438c8a9a5SSteve French 	if (pLockData)
200538c8a9a5SSteve French 		pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
200638c8a9a5SSteve French 	else
200738c8a9a5SSteve French 		pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
200838c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
200938c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
201038c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
201138c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
201238c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
201338c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
201438c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
201538c8a9a5SSteve French 	parm_data = (struct cifs_posix_lock *)
201638c8a9a5SSteve French 			(((char *)pSMB) + offset + 4);
201738c8a9a5SSteve French 
201838c8a9a5SSteve French 	parm_data->lock_type = cpu_to_le16(lock_type);
201938c8a9a5SSteve French 	if (waitFlag) {
202038c8a9a5SSteve French 		timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
202138c8a9a5SSteve French 		parm_data->lock_flags = cpu_to_le16(1);
202238c8a9a5SSteve French 		pSMB->Timeout = cpu_to_le32(-1);
202338c8a9a5SSteve French 	} else
202438c8a9a5SSteve French 		pSMB->Timeout = 0;
202538c8a9a5SSteve French 
202638c8a9a5SSteve French 	parm_data->pid = cpu_to_le32(netpid);
202738c8a9a5SSteve French 	parm_data->start = cpu_to_le64(start_offset);
202838c8a9a5SSteve French 	parm_data->length = cpu_to_le64(len);  /* normalize negative numbers */
202938c8a9a5SSteve French 
203038c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
203138c8a9a5SSteve French 	pSMB->Fid = smb_file_id;
203238c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
203338c8a9a5SSteve French 	pSMB->Reserved4 = 0;
203438c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
203538c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
203638c8a9a5SSteve French 	if (waitFlag) {
203738c8a9a5SSteve French 		rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
203838c8a9a5SSteve French 			(struct smb_hdr *) pSMBr, &bytes_returned);
203938c8a9a5SSteve French 	} else {
204038c8a9a5SSteve French 		iov[0].iov_base = (char *)pSMB;
204138c8a9a5SSteve French 		iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
204238c8a9a5SSteve French 		rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
204338c8a9a5SSteve French 				&resp_buf_type, timeout, &rsp_iov);
204438c8a9a5SSteve French 		pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
204538c8a9a5SSteve French 	}
204638c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
204738c8a9a5SSteve French 
204838c8a9a5SSteve French 	if (rc) {
204938c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
205038c8a9a5SSteve French 	} else if (pLockData) {
205138c8a9a5SSteve French 		/* lock structure can be returned on get */
205238c8a9a5SSteve French 		__u16 data_offset;
205338c8a9a5SSteve French 		__u16 data_count;
205438c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
205538c8a9a5SSteve French 
205638c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
205738c8a9a5SSteve French 			rc = -EIO;      /* bad smb */
205838c8a9a5SSteve French 			goto plk_err_exit;
205938c8a9a5SSteve French 		}
206038c8a9a5SSteve French 		data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
206138c8a9a5SSteve French 		data_count  = le16_to_cpu(pSMBr->t2.DataCount);
206238c8a9a5SSteve French 		if (data_count < sizeof(struct cifs_posix_lock)) {
206338c8a9a5SSteve French 			rc = -EIO;
206438c8a9a5SSteve French 			goto plk_err_exit;
206538c8a9a5SSteve French 		}
206638c8a9a5SSteve French 		parm_data = (struct cifs_posix_lock *)
206738c8a9a5SSteve French 			((char *)&pSMBr->hdr.Protocol + data_offset);
206838c8a9a5SSteve French 		if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
206938c8a9a5SSteve French 			pLockData->fl_type = F_UNLCK;
207038c8a9a5SSteve French 		else {
207138c8a9a5SSteve French 			if (parm_data->lock_type ==
207238c8a9a5SSteve French 					cpu_to_le16(CIFS_RDLCK))
207338c8a9a5SSteve French 				pLockData->fl_type = F_RDLCK;
207438c8a9a5SSteve French 			else if (parm_data->lock_type ==
207538c8a9a5SSteve French 					cpu_to_le16(CIFS_WRLCK))
207638c8a9a5SSteve French 				pLockData->fl_type = F_WRLCK;
207738c8a9a5SSteve French 
207838c8a9a5SSteve French 			pLockData->fl_start = le64_to_cpu(parm_data->start);
207938c8a9a5SSteve French 			pLockData->fl_end = pLockData->fl_start +
208038c8a9a5SSteve French 				(le64_to_cpu(parm_data->length) ?
208138c8a9a5SSteve French 				 le64_to_cpu(parm_data->length) - 1 : 0);
208238c8a9a5SSteve French 			pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
208338c8a9a5SSteve French 		}
208438c8a9a5SSteve French 	}
208538c8a9a5SSteve French 
208638c8a9a5SSteve French plk_err_exit:
208738c8a9a5SSteve French 	free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
208838c8a9a5SSteve French 
208938c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
209038c8a9a5SSteve French 	   since file handle passed in no longer valid */
209138c8a9a5SSteve French 
209238c8a9a5SSteve French 	return rc;
209338c8a9a5SSteve French }
209438c8a9a5SSteve French 
209538c8a9a5SSteve French 
209638c8a9a5SSteve French int
CIFSSMBClose(const unsigned int xid,struct cifs_tcon * tcon,int smb_file_id)209738c8a9a5SSteve French CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
209838c8a9a5SSteve French {
209938c8a9a5SSteve French 	int rc = 0;
210038c8a9a5SSteve French 	CLOSE_REQ *pSMB = NULL;
210138c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSSMBClose\n");
210238c8a9a5SSteve French 
210338c8a9a5SSteve French /* do not retry on dead session on close */
210438c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
210538c8a9a5SSteve French 	if (rc == -EAGAIN)
210638c8a9a5SSteve French 		return 0;
210738c8a9a5SSteve French 	if (rc)
210838c8a9a5SSteve French 		return rc;
210938c8a9a5SSteve French 
211038c8a9a5SSteve French 	pSMB->FileID = (__u16) smb_file_id;
211138c8a9a5SSteve French 	pSMB->LastWriteTime = 0xFFFFFFFF;
211238c8a9a5SSteve French 	pSMB->ByteCount = 0;
211338c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
211438c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
211538c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
211638c8a9a5SSteve French 	if (rc) {
211738c8a9a5SSteve French 		if (rc != -EINTR) {
211838c8a9a5SSteve French 			/* EINTR is expected when user ctl-c to kill app */
211938c8a9a5SSteve French 			cifs_dbg(VFS, "Send error in Close = %d\n", rc);
212038c8a9a5SSteve French 		}
212138c8a9a5SSteve French 	}
212238c8a9a5SSteve French 
212338c8a9a5SSteve French 	/* Since session is dead, file will be closed on server already */
212438c8a9a5SSteve French 	if (rc == -EAGAIN)
212538c8a9a5SSteve French 		rc = 0;
212638c8a9a5SSteve French 
212738c8a9a5SSteve French 	return rc;
212838c8a9a5SSteve French }
212938c8a9a5SSteve French 
213038c8a9a5SSteve French int
CIFSSMBFlush(const unsigned int xid,struct cifs_tcon * tcon,int smb_file_id)213138c8a9a5SSteve French CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
213238c8a9a5SSteve French {
213338c8a9a5SSteve French 	int rc = 0;
213438c8a9a5SSteve French 	FLUSH_REQ *pSMB = NULL;
213538c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSSMBFlush\n");
213638c8a9a5SSteve French 
213738c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
213838c8a9a5SSteve French 	if (rc)
213938c8a9a5SSteve French 		return rc;
214038c8a9a5SSteve French 
214138c8a9a5SSteve French 	pSMB->FileID = (__u16) smb_file_id;
214238c8a9a5SSteve French 	pSMB->ByteCount = 0;
214338c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
214438c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
214538c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
214638c8a9a5SSteve French 	if (rc)
214738c8a9a5SSteve French 		cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
214838c8a9a5SSteve French 
214938c8a9a5SSteve French 	return rc;
215038c8a9a5SSteve French }
215138c8a9a5SSteve French 
CIFSSMBRename(const unsigned int xid,struct cifs_tcon * tcon,struct dentry * source_dentry,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)2152c586b0c7SPaulo Alcantara int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2153c586b0c7SPaulo Alcantara 		  struct dentry *source_dentry,
215438c8a9a5SSteve French 		  const char *from_name, const char *to_name,
215538c8a9a5SSteve French 		  struct cifs_sb_info *cifs_sb)
215638c8a9a5SSteve French {
215738c8a9a5SSteve French 	int rc = 0;
215838c8a9a5SSteve French 	RENAME_REQ *pSMB = NULL;
215938c8a9a5SSteve French 	RENAME_RSP *pSMBr = NULL;
216038c8a9a5SSteve French 	int bytes_returned;
216138c8a9a5SSteve French 	int name_len, name_len2;
216238c8a9a5SSteve French 	__u16 count;
216338c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
216438c8a9a5SSteve French 
216538c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSSMBRename\n");
216638c8a9a5SSteve French renameRetry:
216738c8a9a5SSteve French 	rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
216838c8a9a5SSteve French 		      (void **) &pSMBr);
216938c8a9a5SSteve French 	if (rc)
217038c8a9a5SSteve French 		return rc;
217138c8a9a5SSteve French 
217238c8a9a5SSteve French 	pSMB->BufferFormat = 0x04;
217338c8a9a5SSteve French 	pSMB->SearchAttributes =
217438c8a9a5SSteve French 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
217538c8a9a5SSteve French 			ATTR_DIRECTORY);
217638c8a9a5SSteve French 
217738c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
217838c8a9a5SSteve French 		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
217938c8a9a5SSteve French 					      from_name, PATH_MAX,
218038c8a9a5SSteve French 					      cifs_sb->local_nls, remap);
218138c8a9a5SSteve French 		name_len++;	/* trailing null */
218238c8a9a5SSteve French 		name_len *= 2;
218338c8a9a5SSteve French 		pSMB->OldFileName[name_len] = 0x04;	/* pad */
218438c8a9a5SSteve French 	/* protocol requires ASCII signature byte on Unicode string */
218538c8a9a5SSteve French 		pSMB->OldFileName[name_len + 1] = 0x00;
218638c8a9a5SSteve French 		name_len2 =
218738c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
218838c8a9a5SSteve French 				       to_name, PATH_MAX, cifs_sb->local_nls,
218938c8a9a5SSteve French 				       remap);
219038c8a9a5SSteve French 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
219138c8a9a5SSteve French 		name_len2 *= 2;	/* convert to bytes */
219238c8a9a5SSteve French 	} else {
219338c8a9a5SSteve French 		name_len = copy_path_name(pSMB->OldFileName, from_name);
219438c8a9a5SSteve French 		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
219538c8a9a5SSteve French 		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
219638c8a9a5SSteve French 		name_len2++;	/* signature byte */
219738c8a9a5SSteve French 	}
219838c8a9a5SSteve French 
219938c8a9a5SSteve French 	count = 1 /* 1st signature byte */  + name_len + name_len2;
220038c8a9a5SSteve French 	inc_rfc1001_len(pSMB, count);
220138c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(count);
220238c8a9a5SSteve French 
220338c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
220438c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
220538c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
220638c8a9a5SSteve French 	if (rc)
220738c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in rename = %d\n", rc);
220838c8a9a5SSteve French 
220938c8a9a5SSteve French 	cifs_buf_release(pSMB);
221038c8a9a5SSteve French 
221138c8a9a5SSteve French 	if (rc == -EAGAIN)
221238c8a9a5SSteve French 		goto renameRetry;
221338c8a9a5SSteve French 
221438c8a9a5SSteve French 	return rc;
221538c8a9a5SSteve French }
221638c8a9a5SSteve French 
CIFSSMBRenameOpenFile(const unsigned int xid,struct cifs_tcon * pTcon,int netfid,const char * target_name,const struct nls_table * nls_codepage,int remap)221738c8a9a5SSteve French int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
221838c8a9a5SSteve French 		int netfid, const char *target_name,
221938c8a9a5SSteve French 		const struct nls_table *nls_codepage, int remap)
222038c8a9a5SSteve French {
222138c8a9a5SSteve French 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
222238c8a9a5SSteve French 	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
222338c8a9a5SSteve French 	struct set_file_rename *rename_info;
222438c8a9a5SSteve French 	char *data_offset;
222538c8a9a5SSteve French 	char dummy_string[30];
222638c8a9a5SSteve French 	int rc = 0;
222738c8a9a5SSteve French 	int bytes_returned = 0;
222838c8a9a5SSteve French 	int len_of_str;
222938c8a9a5SSteve French 	__u16 params, param_offset, offset, count, byte_count;
223038c8a9a5SSteve French 
223138c8a9a5SSteve French 	cifs_dbg(FYI, "Rename to File by handle\n");
223238c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
223338c8a9a5SSteve French 			(void **) &pSMBr);
223438c8a9a5SSteve French 	if (rc)
223538c8a9a5SSteve French 		return rc;
223638c8a9a5SSteve French 
223738c8a9a5SSteve French 	params = 6;
223838c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
223938c8a9a5SSteve French 	pSMB->Reserved = 0;
224038c8a9a5SSteve French 	pSMB->Flags = 0;
224138c8a9a5SSteve French 	pSMB->Timeout = 0;
224238c8a9a5SSteve French 	pSMB->Reserved2 = 0;
224338c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
224438c8a9a5SSteve French 	offset = param_offset + params;
224538c8a9a5SSteve French 
224638c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
224738c8a9a5SSteve French 	data_offset = (char *)(pSMB) + offset + 4;
224838c8a9a5SSteve French 	rename_info = (struct set_file_rename *) data_offset;
224938c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
225038c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
225138c8a9a5SSteve French 	pSMB->SetupCount = 1;
225238c8a9a5SSteve French 	pSMB->Reserved3 = 0;
225338c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
225438c8a9a5SSteve French 	byte_count = 3 /* pad */  + params;
225538c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
225638c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
225738c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
225838c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
225938c8a9a5SSteve French 	/* construct random name ".cifs_tmp<inodenum><mid>" */
226038c8a9a5SSteve French 	rename_info->overwrite = cpu_to_le32(1);
226138c8a9a5SSteve French 	rename_info->root_fid  = 0;
226238c8a9a5SSteve French 	/* unicode only call */
226338c8a9a5SSteve French 	if (target_name == NULL) {
226438c8a9a5SSteve French 		sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
226538c8a9a5SSteve French 		len_of_str =
226638c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *)rename_info->target_name,
226738c8a9a5SSteve French 					dummy_string, 24, nls_codepage, remap);
226838c8a9a5SSteve French 	} else {
226938c8a9a5SSteve French 		len_of_str =
227038c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *)rename_info->target_name,
227138c8a9a5SSteve French 					target_name, PATH_MAX, nls_codepage,
227238c8a9a5SSteve French 					remap);
227338c8a9a5SSteve French 	}
227438c8a9a5SSteve French 	rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
227538c8a9a5SSteve French 	count = sizeof(struct set_file_rename) + (2 * len_of_str);
227638c8a9a5SSteve French 	byte_count += count;
227738c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
227838c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
227938c8a9a5SSteve French 	pSMB->Fid = netfid;
228038c8a9a5SSteve French 	pSMB->InformationLevel =
228138c8a9a5SSteve French 		cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
228238c8a9a5SSteve French 	pSMB->Reserved4 = 0;
228338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
228438c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
228538c8a9a5SSteve French 	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
228638c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
228738c8a9a5SSteve French 	cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
228838c8a9a5SSteve French 	if (rc)
228938c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
229038c8a9a5SSteve French 			 rc);
229138c8a9a5SSteve French 
229238c8a9a5SSteve French 	cifs_buf_release(pSMB);
229338c8a9a5SSteve French 
229438c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
229538c8a9a5SSteve French 		since file handle passed in no longer valid */
229638c8a9a5SSteve French 
229738c8a9a5SSteve French 	return rc;
229838c8a9a5SSteve French }
229938c8a9a5SSteve French 
230038c8a9a5SSteve French int
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)230138c8a9a5SSteve French CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
230238c8a9a5SSteve French 	    const char *fromName, const __u16 target_tid, const char *toName,
230338c8a9a5SSteve French 	    const int flags, const struct nls_table *nls_codepage, int remap)
230438c8a9a5SSteve French {
230538c8a9a5SSteve French 	int rc = 0;
230638c8a9a5SSteve French 	COPY_REQ *pSMB = NULL;
230738c8a9a5SSteve French 	COPY_RSP *pSMBr = NULL;
230838c8a9a5SSteve French 	int bytes_returned;
230938c8a9a5SSteve French 	int name_len, name_len2;
231038c8a9a5SSteve French 	__u16 count;
231138c8a9a5SSteve French 
231238c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSSMBCopy\n");
231338c8a9a5SSteve French copyRetry:
231438c8a9a5SSteve French 	rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
231538c8a9a5SSteve French 			(void **) &pSMBr);
231638c8a9a5SSteve French 	if (rc)
231738c8a9a5SSteve French 		return rc;
231838c8a9a5SSteve French 
231938c8a9a5SSteve French 	pSMB->BufferFormat = 0x04;
232038c8a9a5SSteve French 	pSMB->Tid2 = target_tid;
232138c8a9a5SSteve French 
232238c8a9a5SSteve French 	pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
232338c8a9a5SSteve French 
232438c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
232538c8a9a5SSteve French 		name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
232638c8a9a5SSteve French 					      fromName, PATH_MAX, nls_codepage,
232738c8a9a5SSteve French 					      remap);
232838c8a9a5SSteve French 		name_len++;     /* trailing null */
232938c8a9a5SSteve French 		name_len *= 2;
233038c8a9a5SSteve French 		pSMB->OldFileName[name_len] = 0x04;     /* pad */
233138c8a9a5SSteve French 		/* protocol requires ASCII signature byte on Unicode string */
233238c8a9a5SSteve French 		pSMB->OldFileName[name_len + 1] = 0x00;
233338c8a9a5SSteve French 		name_len2 =
233438c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
233538c8a9a5SSteve French 				       toName, PATH_MAX, nls_codepage, remap);
233638c8a9a5SSteve French 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
233738c8a9a5SSteve French 		name_len2 *= 2; /* convert to bytes */
233838c8a9a5SSteve French 	} else {
233938c8a9a5SSteve French 		name_len = copy_path_name(pSMB->OldFileName, fromName);
234038c8a9a5SSteve French 		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
234138c8a9a5SSteve French 		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
234238c8a9a5SSteve French 		name_len2++;    /* signature byte */
234338c8a9a5SSteve French 	}
234438c8a9a5SSteve French 
234538c8a9a5SSteve French 	count = 1 /* 1st signature byte */  + name_len + name_len2;
234638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, count);
234738c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(count);
234838c8a9a5SSteve French 
234938c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
235038c8a9a5SSteve French 		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
235138c8a9a5SSteve French 	if (rc) {
235238c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
235338c8a9a5SSteve French 			 rc, le16_to_cpu(pSMBr->CopyCount));
235438c8a9a5SSteve French 	}
235538c8a9a5SSteve French 	cifs_buf_release(pSMB);
235638c8a9a5SSteve French 
235738c8a9a5SSteve French 	if (rc == -EAGAIN)
235838c8a9a5SSteve French 		goto copyRetry;
235938c8a9a5SSteve French 
236038c8a9a5SSteve French 	return rc;
236138c8a9a5SSteve French }
236238c8a9a5SSteve French 
236338c8a9a5SSteve French int
CIFSUnixCreateSymLink(const unsigned int xid,struct cifs_tcon * tcon,const char * fromName,const char * toName,const struct nls_table * nls_codepage,int remap)236438c8a9a5SSteve French CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
236538c8a9a5SSteve French 		      const char *fromName, const char *toName,
236638c8a9a5SSteve French 		      const struct nls_table *nls_codepage, int remap)
236738c8a9a5SSteve French {
236838c8a9a5SSteve French 	TRANSACTION2_SPI_REQ *pSMB = NULL;
236938c8a9a5SSteve French 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
237038c8a9a5SSteve French 	char *data_offset;
237138c8a9a5SSteve French 	int name_len;
237238c8a9a5SSteve French 	int name_len_target;
237338c8a9a5SSteve French 	int rc = 0;
237438c8a9a5SSteve French 	int bytes_returned = 0;
237538c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count;
237638c8a9a5SSteve French 
237738c8a9a5SSteve French 	cifs_dbg(FYI, "In Symlink Unix style\n");
237838c8a9a5SSteve French createSymLinkRetry:
237938c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
238038c8a9a5SSteve French 		      (void **) &pSMBr);
238138c8a9a5SSteve French 	if (rc)
238238c8a9a5SSteve French 		return rc;
238338c8a9a5SSteve French 
238438c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
238538c8a9a5SSteve French 		name_len =
238638c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
238738c8a9a5SSteve French 				/* find define for this maxpathcomponent */
238838c8a9a5SSteve French 					PATH_MAX, nls_codepage, remap);
238938c8a9a5SSteve French 		name_len++;	/* trailing null */
239038c8a9a5SSteve French 		name_len *= 2;
239138c8a9a5SSteve French 
239238c8a9a5SSteve French 	} else {
239338c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, fromName);
239438c8a9a5SSteve French 	}
239538c8a9a5SSteve French 	params = 6 + name_len;
239638c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
239738c8a9a5SSteve French 	pSMB->Reserved = 0;
239838c8a9a5SSteve French 	pSMB->Flags = 0;
239938c8a9a5SSteve French 	pSMB->Timeout = 0;
240038c8a9a5SSteve French 	pSMB->Reserved2 = 0;
240138c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
240238c8a9a5SSteve French 				InformationLevel) - 4;
240338c8a9a5SSteve French 	offset = param_offset + params;
240438c8a9a5SSteve French 
240538c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
240638c8a9a5SSteve French 	data_offset = (char *)pSMB + offset + 4;
240738c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
240838c8a9a5SSteve French 		name_len_target =
240938c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) data_offset, toName,
241038c8a9a5SSteve French 				/* find define for this maxpathcomponent */
241138c8a9a5SSteve French 					PATH_MAX, nls_codepage, remap);
241238c8a9a5SSteve French 		name_len_target++;	/* trailing null */
241338c8a9a5SSteve French 		name_len_target *= 2;
241438c8a9a5SSteve French 	} else {
241538c8a9a5SSteve French 		name_len_target = copy_path_name(data_offset, toName);
241638c8a9a5SSteve French 	}
241738c8a9a5SSteve French 
241838c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
241938c8a9a5SSteve French 	/* BB find exact max on data count below from sess */
242038c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
242138c8a9a5SSteve French 	pSMB->SetupCount = 1;
242238c8a9a5SSteve French 	pSMB->Reserved3 = 0;
242338c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
242438c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + name_len_target;
242538c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(name_len_target);
242638c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
242738c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
242838c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
242938c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
243038c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
243138c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
243238c8a9a5SSteve French 	pSMB->Reserved4 = 0;
243338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
243438c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
243538c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
243638c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
243738c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
243838c8a9a5SSteve French 	if (rc)
243938c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
244038c8a9a5SSteve French 			 rc);
244138c8a9a5SSteve French 
244238c8a9a5SSteve French 	cifs_buf_release(pSMB);
244338c8a9a5SSteve French 
244438c8a9a5SSteve French 	if (rc == -EAGAIN)
244538c8a9a5SSteve French 		goto createSymLinkRetry;
244638c8a9a5SSteve French 
244738c8a9a5SSteve French 	return rc;
244838c8a9a5SSteve French }
244938c8a9a5SSteve French 
245038c8a9a5SSteve French int
CIFSUnixCreateHardLink(const unsigned int xid,struct cifs_tcon * tcon,const char * fromName,const char * toName,const struct nls_table * nls_codepage,int remap)245138c8a9a5SSteve French CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
245238c8a9a5SSteve French 		       const char *fromName, const char *toName,
245338c8a9a5SSteve French 		       const struct nls_table *nls_codepage, int remap)
245438c8a9a5SSteve French {
245538c8a9a5SSteve French 	TRANSACTION2_SPI_REQ *pSMB = NULL;
245638c8a9a5SSteve French 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
245738c8a9a5SSteve French 	char *data_offset;
245838c8a9a5SSteve French 	int name_len;
245938c8a9a5SSteve French 	int name_len_target;
246038c8a9a5SSteve French 	int rc = 0;
246138c8a9a5SSteve French 	int bytes_returned = 0;
246238c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count;
246338c8a9a5SSteve French 
246438c8a9a5SSteve French 	cifs_dbg(FYI, "In Create Hard link Unix style\n");
246538c8a9a5SSteve French createHardLinkRetry:
246638c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
246738c8a9a5SSteve French 		      (void **) &pSMBr);
246838c8a9a5SSteve French 	if (rc)
246938c8a9a5SSteve French 		return rc;
247038c8a9a5SSteve French 
247138c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
247238c8a9a5SSteve French 		name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
247338c8a9a5SSteve French 					      PATH_MAX, nls_codepage, remap);
247438c8a9a5SSteve French 		name_len++;	/* trailing null */
247538c8a9a5SSteve French 		name_len *= 2;
247638c8a9a5SSteve French 
247738c8a9a5SSteve French 	} else {
247838c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, toName);
247938c8a9a5SSteve French 	}
248038c8a9a5SSteve French 	params = 6 + name_len;
248138c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
248238c8a9a5SSteve French 	pSMB->Reserved = 0;
248338c8a9a5SSteve French 	pSMB->Flags = 0;
248438c8a9a5SSteve French 	pSMB->Timeout = 0;
248538c8a9a5SSteve French 	pSMB->Reserved2 = 0;
248638c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
248738c8a9a5SSteve French 				InformationLevel) - 4;
248838c8a9a5SSteve French 	offset = param_offset + params;
248938c8a9a5SSteve French 
249038c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
249138c8a9a5SSteve French 	data_offset = (char *)pSMB + offset + 4;
249238c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
249338c8a9a5SSteve French 		name_len_target =
249438c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) data_offset, fromName,
249538c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
249638c8a9a5SSteve French 		name_len_target++;	/* trailing null */
249738c8a9a5SSteve French 		name_len_target *= 2;
249838c8a9a5SSteve French 	} else {
249938c8a9a5SSteve French 		name_len_target = copy_path_name(data_offset, fromName);
250038c8a9a5SSteve French 	}
250138c8a9a5SSteve French 
250238c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
250338c8a9a5SSteve French 	/* BB find exact max on data count below from sess*/
250438c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
250538c8a9a5SSteve French 	pSMB->SetupCount = 1;
250638c8a9a5SSteve French 	pSMB->Reserved3 = 0;
250738c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
250838c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + name_len_target;
250938c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
251038c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
251138c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(name_len_target);
251238c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
251338c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
251438c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
251538c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
251638c8a9a5SSteve French 	pSMB->Reserved4 = 0;
251738c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
251838c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
251938c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
252038c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
252138c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
252238c8a9a5SSteve French 	if (rc)
252338c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
252438c8a9a5SSteve French 			 rc);
252538c8a9a5SSteve French 
252638c8a9a5SSteve French 	cifs_buf_release(pSMB);
252738c8a9a5SSteve French 	if (rc == -EAGAIN)
252838c8a9a5SSteve French 		goto createHardLinkRetry;
252938c8a9a5SSteve French 
253038c8a9a5SSteve French 	return rc;
253138c8a9a5SSteve French }
253238c8a9a5SSteve French 
CIFSCreateHardLink(const unsigned int xid,struct cifs_tcon * tcon,struct dentry * source_dentry,const char * from_name,const char * to_name,struct cifs_sb_info * cifs_sb)25338c944f8aSPaulo Alcantara int CIFSCreateHardLink(const unsigned int xid,
25348c944f8aSPaulo Alcantara 		       struct cifs_tcon *tcon,
25358c944f8aSPaulo Alcantara 		       struct dentry *source_dentry,
253638c8a9a5SSteve French 		       const char *from_name, const char *to_name,
253738c8a9a5SSteve French 		       struct cifs_sb_info *cifs_sb)
253838c8a9a5SSteve French {
253938c8a9a5SSteve French 	int rc = 0;
254038c8a9a5SSteve French 	NT_RENAME_REQ *pSMB = NULL;
254138c8a9a5SSteve French 	RENAME_RSP *pSMBr = NULL;
254238c8a9a5SSteve French 	int bytes_returned;
254338c8a9a5SSteve French 	int name_len, name_len2;
254438c8a9a5SSteve French 	__u16 count;
254538c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
254638c8a9a5SSteve French 
254738c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSCreateHardLink\n");
254838c8a9a5SSteve French winCreateHardLinkRetry:
254938c8a9a5SSteve French 
255038c8a9a5SSteve French 	rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
255138c8a9a5SSteve French 		      (void **) &pSMBr);
255238c8a9a5SSteve French 	if (rc)
255338c8a9a5SSteve French 		return rc;
255438c8a9a5SSteve French 
255538c8a9a5SSteve French 	pSMB->SearchAttributes =
255638c8a9a5SSteve French 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
255738c8a9a5SSteve French 			ATTR_DIRECTORY);
255838c8a9a5SSteve French 	pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
255938c8a9a5SSteve French 	pSMB->ClusterCount = 0;
256038c8a9a5SSteve French 
256138c8a9a5SSteve French 	pSMB->BufferFormat = 0x04;
256238c8a9a5SSteve French 
256338c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
256438c8a9a5SSteve French 		name_len =
256538c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
256638c8a9a5SSteve French 				       PATH_MAX, cifs_sb->local_nls, remap);
256738c8a9a5SSteve French 		name_len++;	/* trailing null */
256838c8a9a5SSteve French 		name_len *= 2;
256938c8a9a5SSteve French 
257038c8a9a5SSteve French 		/* protocol specifies ASCII buffer format (0x04) for unicode */
257138c8a9a5SSteve French 		pSMB->OldFileName[name_len] = 0x04;
257238c8a9a5SSteve French 		pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
257338c8a9a5SSteve French 		name_len2 =
257438c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
257538c8a9a5SSteve French 				       to_name, PATH_MAX, cifs_sb->local_nls,
257638c8a9a5SSteve French 				       remap);
257738c8a9a5SSteve French 		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
257838c8a9a5SSteve French 		name_len2 *= 2;	/* convert to bytes */
257938c8a9a5SSteve French 	} else {
258038c8a9a5SSteve French 		name_len = copy_path_name(pSMB->OldFileName, from_name);
258138c8a9a5SSteve French 		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
258238c8a9a5SSteve French 		name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, to_name);
258338c8a9a5SSteve French 		name_len2++;	/* signature byte */
258438c8a9a5SSteve French 	}
258538c8a9a5SSteve French 
258638c8a9a5SSteve French 	count = 1 /* string type byte */  + name_len + name_len2;
258738c8a9a5SSteve French 	inc_rfc1001_len(pSMB, count);
258838c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(count);
258938c8a9a5SSteve French 
259038c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
259138c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
259238c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
259338c8a9a5SSteve French 	if (rc)
259438c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
259538c8a9a5SSteve French 
259638c8a9a5SSteve French 	cifs_buf_release(pSMB);
259738c8a9a5SSteve French 	if (rc == -EAGAIN)
259838c8a9a5SSteve French 		goto winCreateHardLinkRetry;
259938c8a9a5SSteve French 
260038c8a9a5SSteve French 	return rc;
260138c8a9a5SSteve French }
260238c8a9a5SSteve French 
260338c8a9a5SSteve French int
CIFSSMBUnixQuerySymLink(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,char ** symlinkinfo,const struct nls_table * nls_codepage,int remap)260438c8a9a5SSteve French CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
260538c8a9a5SSteve French 			const unsigned char *searchName, char **symlinkinfo,
260638c8a9a5SSteve French 			const struct nls_table *nls_codepage, int remap)
260738c8a9a5SSteve French {
260838c8a9a5SSteve French /* SMB_QUERY_FILE_UNIX_LINK */
260938c8a9a5SSteve French 	TRANSACTION2_QPI_REQ *pSMB = NULL;
261038c8a9a5SSteve French 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
261138c8a9a5SSteve French 	int rc = 0;
261238c8a9a5SSteve French 	int bytes_returned;
261338c8a9a5SSteve French 	int name_len;
261438c8a9a5SSteve French 	__u16 params, byte_count;
261538c8a9a5SSteve French 	char *data_start;
261638c8a9a5SSteve French 
261738c8a9a5SSteve French 	cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
261838c8a9a5SSteve French 
261938c8a9a5SSteve French querySymLinkRetry:
262038c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
262138c8a9a5SSteve French 		      (void **) &pSMBr);
262238c8a9a5SSteve French 	if (rc)
262338c8a9a5SSteve French 		return rc;
262438c8a9a5SSteve French 
262538c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
262638c8a9a5SSteve French 		name_len =
262738c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *) pSMB->FileName,
262838c8a9a5SSteve French 					   searchName, PATH_MAX, nls_codepage,
262938c8a9a5SSteve French 					   remap);
263038c8a9a5SSteve French 		name_len++;	/* trailing null */
263138c8a9a5SSteve French 		name_len *= 2;
263238c8a9a5SSteve French 	} else {
263338c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, searchName);
263438c8a9a5SSteve French 	}
263538c8a9a5SSteve French 
263638c8a9a5SSteve French 	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
263738c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
263838c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
263938c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
264038c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
264138c8a9a5SSteve French 	pSMB->Reserved = 0;
264238c8a9a5SSteve French 	pSMB->Flags = 0;
264338c8a9a5SSteve French 	pSMB->Timeout = 0;
264438c8a9a5SSteve French 	pSMB->Reserved2 = 0;
264538c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
264638c8a9a5SSteve French 	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
264738c8a9a5SSteve French 	pSMB->DataCount = 0;
264838c8a9a5SSteve French 	pSMB->DataOffset = 0;
264938c8a9a5SSteve French 	pSMB->SetupCount = 1;
265038c8a9a5SSteve French 	pSMB->Reserved3 = 0;
265138c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
265238c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
265338c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
265438c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
265538c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
265638c8a9a5SSteve French 	pSMB->Reserved4 = 0;
265738c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
265838c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
265938c8a9a5SSteve French 
266038c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
266138c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
266238c8a9a5SSteve French 	if (rc) {
266338c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
266438c8a9a5SSteve French 	} else {
266538c8a9a5SSteve French 		/* decode response */
266638c8a9a5SSteve French 
266738c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
266838c8a9a5SSteve French 		/* BB also check enough total bytes returned */
266938c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 2)
267038c8a9a5SSteve French 			rc = -EIO;
267138c8a9a5SSteve French 		else {
267238c8a9a5SSteve French 			bool is_unicode;
267338c8a9a5SSteve French 			u16 count = le16_to_cpu(pSMBr->t2.DataCount);
267438c8a9a5SSteve French 
267538c8a9a5SSteve French 			data_start = ((char *) &pSMBr->hdr.Protocol) +
267638c8a9a5SSteve French 					   le16_to_cpu(pSMBr->t2.DataOffset);
267738c8a9a5SSteve French 
267838c8a9a5SSteve French 			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
267938c8a9a5SSteve French 				is_unicode = true;
268038c8a9a5SSteve French 			else
268138c8a9a5SSteve French 				is_unicode = false;
268238c8a9a5SSteve French 
268338c8a9a5SSteve French 			/* BB FIXME investigate remapping reserved chars here */
268438c8a9a5SSteve French 			*symlinkinfo = cifs_strndup_from_utf16(data_start,
268538c8a9a5SSteve French 					count, is_unicode, nls_codepage);
268638c8a9a5SSteve French 			if (!*symlinkinfo)
268738c8a9a5SSteve French 				rc = -ENOMEM;
268838c8a9a5SSteve French 		}
268938c8a9a5SSteve French 	}
269038c8a9a5SSteve French 	cifs_buf_release(pSMB);
269138c8a9a5SSteve French 	if (rc == -EAGAIN)
269238c8a9a5SSteve French 		goto querySymLinkRetry;
269338c8a9a5SSteve French 	return rc;
269438c8a9a5SSteve French }
269538c8a9a5SSteve French 
cifs_query_reparse_point(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,u32 * tag,struct kvec * rsp,int * rsp_buftype)2696d5c959a1SPaulo Alcantara int cifs_query_reparse_point(const unsigned int xid,
2697d5c959a1SPaulo Alcantara 			     struct cifs_tcon *tcon,
2698d5c959a1SPaulo Alcantara 			     struct cifs_sb_info *cifs_sb,
2699d5c959a1SPaulo Alcantara 			     const char *full_path,
2700d5c959a1SPaulo Alcantara 			     u32 *tag, struct kvec *rsp,
2701d5c959a1SPaulo Alcantara 			     int *rsp_buftype)
270238c8a9a5SSteve French {
27038e6a3999SPaulo Alcantara 	struct reparse_data_buffer *buf;
2704d5c959a1SPaulo Alcantara 	struct cifs_open_parms oparms;
2705d5c959a1SPaulo Alcantara 	TRANSACT_IOCTL_REQ *io_req = NULL;
2706d5c959a1SPaulo Alcantara 	TRANSACT_IOCTL_RSP *io_rsp = NULL;
2707d5c959a1SPaulo Alcantara 	struct cifs_fid fid;
27088e6a3999SPaulo Alcantara 	__u32 data_offset, data_count, len;
2709d5c959a1SPaulo Alcantara 	__u8 *start, *end;
2710d5c959a1SPaulo Alcantara 	int io_rsp_len;
2711d5c959a1SPaulo Alcantara 	int oplock = 0;
2712d5c959a1SPaulo Alcantara 	int rc;
271338c8a9a5SSteve French 
2714d5c959a1SPaulo Alcantara 	cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
2715d5c959a1SPaulo Alcantara 
2716d5c959a1SPaulo Alcantara 	if (cap_unix(tcon->ses))
2717d5c959a1SPaulo Alcantara 		return -EOPNOTSUPP;
2718d5c959a1SPaulo Alcantara 
2719d5c959a1SPaulo Alcantara 	oparms = (struct cifs_open_parms) {
2720d5c959a1SPaulo Alcantara 		.tcon = tcon,
2721d5c959a1SPaulo Alcantara 		.cifs_sb = cifs_sb,
2722d5c959a1SPaulo Alcantara 		.desired_access = FILE_READ_ATTRIBUTES,
2723d5c959a1SPaulo Alcantara 		.create_options = cifs_create_options(cifs_sb,
2724d5c959a1SPaulo Alcantara 						      OPEN_REPARSE_POINT),
2725d5c959a1SPaulo Alcantara 		.disposition = FILE_OPEN,
2726d5c959a1SPaulo Alcantara 		.path = full_path,
2727d5c959a1SPaulo Alcantara 		.fid = &fid,
2728d5c959a1SPaulo Alcantara 	};
2729d5c959a1SPaulo Alcantara 
2730d5c959a1SPaulo Alcantara 	rc = CIFS_open(xid, &oparms, &oplock, NULL);
273138c8a9a5SSteve French 	if (rc)
273238c8a9a5SSteve French 		return rc;
273338c8a9a5SSteve French 
2734d5c959a1SPaulo Alcantara 	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon,
2735d5c959a1SPaulo Alcantara 		      (void **)&io_req, (void **)&io_rsp);
2736d5c959a1SPaulo Alcantara 	if (rc)
2737d5c959a1SPaulo Alcantara 		goto error;
2738d5c959a1SPaulo Alcantara 
2739d5c959a1SPaulo Alcantara 	io_req->TotalParameterCount = 0;
2740d5c959a1SPaulo Alcantara 	io_req->TotalDataCount = 0;
2741d5c959a1SPaulo Alcantara 	io_req->MaxParameterCount = cpu_to_le32(2);
274238c8a9a5SSteve French 	/* BB find exact data count max from sess structure BB */
2743d5c959a1SPaulo Alcantara 	io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
2744d5c959a1SPaulo Alcantara 	io_req->MaxSetupCount = 4;
2745d5c959a1SPaulo Alcantara 	io_req->Reserved = 0;
2746d5c959a1SPaulo Alcantara 	io_req->ParameterOffset = 0;
2747d5c959a1SPaulo Alcantara 	io_req->DataCount = 0;
2748d5c959a1SPaulo Alcantara 	io_req->DataOffset = 0;
2749d5c959a1SPaulo Alcantara 	io_req->SetupCount = 4;
2750d5c959a1SPaulo Alcantara 	io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2751d5c959a1SPaulo Alcantara 	io_req->ParameterCount = io_req->TotalParameterCount;
2752d5c959a1SPaulo Alcantara 	io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2753d5c959a1SPaulo Alcantara 	io_req->IsFsctl = 1;
2754d5c959a1SPaulo Alcantara 	io_req->IsRootFlag = 0;
2755d5c959a1SPaulo Alcantara 	io_req->Fid = fid.netfid;
2756d5c959a1SPaulo Alcantara 	io_req->ByteCount = 0;
275738c8a9a5SSteve French 
2758d5c959a1SPaulo Alcantara 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req,
2759d5c959a1SPaulo Alcantara 			 (struct smb_hdr *)io_rsp, &io_rsp_len, 0);
2760d5c959a1SPaulo Alcantara 	if (rc)
2761d5c959a1SPaulo Alcantara 		goto error;
276238c8a9a5SSteve French 
2763d5c959a1SPaulo Alcantara 	data_offset = le32_to_cpu(io_rsp->DataOffset);
2764d5c959a1SPaulo Alcantara 	data_count = le32_to_cpu(io_rsp->DataCount);
2765d5c959a1SPaulo Alcantara 	if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 ||
2766d5c959a1SPaulo Alcantara 	    !data_count || data_count > 2048) {
276738c8a9a5SSteve French 		rc = -EIO;
2768d5c959a1SPaulo Alcantara 		goto error;
276938c8a9a5SSteve French 	}
2770d5c959a1SPaulo Alcantara 
2771d5c959a1SPaulo Alcantara 	end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
2772d5c959a1SPaulo Alcantara 	start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
2773d5c959a1SPaulo Alcantara 	if (start >= end) {
277438c8a9a5SSteve French 		rc = -EIO;
2775d5c959a1SPaulo Alcantara 		goto error;
277638c8a9a5SSteve French 	}
277738c8a9a5SSteve French 
27788e6a3999SPaulo Alcantara 	data_count = le16_to_cpu(io_rsp->ByteCount);
27798e6a3999SPaulo Alcantara 	buf = (struct reparse_data_buffer *)start;
27808e6a3999SPaulo Alcantara 	len = sizeof(*buf);
27818e6a3999SPaulo Alcantara 	if (data_count < len ||
27828e6a3999SPaulo Alcantara 	    data_count < le16_to_cpu(buf->ReparseDataLength) + len) {
27838e6a3999SPaulo Alcantara 		rc = -EIO;
27848e6a3999SPaulo Alcantara 		goto error;
27858e6a3999SPaulo Alcantara 	}
27868e6a3999SPaulo Alcantara 
27878e6a3999SPaulo Alcantara 	*tag = le32_to_cpu(buf->ReparseTag);
2788d5c959a1SPaulo Alcantara 	rsp->iov_base = io_rsp;
2789d5c959a1SPaulo Alcantara 	rsp->iov_len = io_rsp_len;
2790d5c959a1SPaulo Alcantara 	*rsp_buftype = CIFS_LARGE_BUFFER;
2791d5c959a1SPaulo Alcantara 	CIFSSMBClose(xid, tcon, fid.netfid);
2792d5c959a1SPaulo Alcantara 	return 0;
279338c8a9a5SSteve French 
2794d5c959a1SPaulo Alcantara error:
2795d5c959a1SPaulo Alcantara 	cifs_buf_release(io_req);
2796d5c959a1SPaulo Alcantara 	CIFSSMBClose(xid, tcon, fid.netfid);
279738c8a9a5SSteve French 	return rc;
279838c8a9a5SSteve French }
279938c8a9a5SSteve French 
280038c8a9a5SSteve French int
CIFSSMB_set_compression(const unsigned int xid,struct cifs_tcon * tcon,__u16 fid)280138c8a9a5SSteve French CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
280238c8a9a5SSteve French 		    __u16 fid)
280338c8a9a5SSteve French {
280438c8a9a5SSteve French 	int rc = 0;
280538c8a9a5SSteve French 	int bytes_returned;
280638c8a9a5SSteve French 	struct smb_com_transaction_compr_ioctl_req *pSMB;
280738c8a9a5SSteve French 	struct smb_com_transaction_ioctl_rsp *pSMBr;
280838c8a9a5SSteve French 
280938c8a9a5SSteve French 	cifs_dbg(FYI, "Set compression for %u\n", fid);
281038c8a9a5SSteve French 	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
281138c8a9a5SSteve French 		      (void **) &pSMBr);
281238c8a9a5SSteve French 	if (rc)
281338c8a9a5SSteve French 		return rc;
281438c8a9a5SSteve French 
281538c8a9a5SSteve French 	pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
281638c8a9a5SSteve French 
281738c8a9a5SSteve French 	pSMB->TotalParameterCount = 0;
281838c8a9a5SSteve French 	pSMB->TotalDataCount = cpu_to_le32(2);
281938c8a9a5SSteve French 	pSMB->MaxParameterCount = 0;
282038c8a9a5SSteve French 	pSMB->MaxDataCount = 0;
282138c8a9a5SSteve French 	pSMB->MaxSetupCount = 4;
282238c8a9a5SSteve French 	pSMB->Reserved = 0;
282338c8a9a5SSteve French 	pSMB->ParameterOffset = 0;
282438c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le32(2);
282538c8a9a5SSteve French 	pSMB->DataOffset =
282638c8a9a5SSteve French 		cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
282738c8a9a5SSteve French 				compression_state) - 4);  /* 84 */
282838c8a9a5SSteve French 	pSMB->SetupCount = 4;
282938c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
283038c8a9a5SSteve French 	pSMB->ParameterCount = 0;
283138c8a9a5SSteve French 	pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
283238c8a9a5SSteve French 	pSMB->IsFsctl = 1; /* FSCTL */
283338c8a9a5SSteve French 	pSMB->IsRootFlag = 0;
283438c8a9a5SSteve French 	pSMB->Fid = fid; /* file handle always le */
283538c8a9a5SSteve French 	/* 3 byte pad, followed by 2 byte compress state */
283638c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(5);
283738c8a9a5SSteve French 	inc_rfc1001_len(pSMB, 5);
283838c8a9a5SSteve French 
283938c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
284038c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
284138c8a9a5SSteve French 	if (rc)
284238c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
284338c8a9a5SSteve French 
284438c8a9a5SSteve French 	cifs_buf_release(pSMB);
284538c8a9a5SSteve French 
284638c8a9a5SSteve French 	/*
284738c8a9a5SSteve French 	 * Note: On -EAGAIN error only caller can retry on handle based calls
284838c8a9a5SSteve French 	 * since file handle passed in no longer valid.
284938c8a9a5SSteve French 	 */
285038c8a9a5SSteve French 	return rc;
285138c8a9a5SSteve French }
285238c8a9a5SSteve French 
285338c8a9a5SSteve French 
285438c8a9a5SSteve French #ifdef CONFIG_CIFS_POSIX
285538c8a9a5SSteve French 
285638c8a9a5SSteve French #ifdef CONFIG_FS_POSIX_ACL
285738c8a9a5SSteve French /**
285838c8a9a5SSteve French  * cifs_init_posix_acl - convert ACL from cifs to POSIX ACL format
285938c8a9a5SSteve French  * @ace: POSIX ACL entry to store converted ACL into
286038c8a9a5SSteve French  * @cifs_ace: ACL in cifs format
286138c8a9a5SSteve French  *
286238c8a9a5SSteve French  * Convert an Access Control Entry from wire format to local POSIX xattr
286338c8a9a5SSteve French  * format.
286438c8a9a5SSteve French  *
286538c8a9a5SSteve French  * Note that the @cifs_uid member is used to store both {g,u}id_t.
286638c8a9a5SSteve French  */
cifs_init_posix_acl(struct posix_acl_entry * ace,struct cifs_posix_ace * cifs_ace)286738c8a9a5SSteve French static void cifs_init_posix_acl(struct posix_acl_entry *ace,
286838c8a9a5SSteve French 				struct cifs_posix_ace *cifs_ace)
286938c8a9a5SSteve French {
287038c8a9a5SSteve French 	/* u8 cifs fields do not need le conversion */
287138c8a9a5SSteve French 	ace->e_perm = cifs_ace->cifs_e_perm;
287238c8a9a5SSteve French 	ace->e_tag = cifs_ace->cifs_e_tag;
287338c8a9a5SSteve French 
287438c8a9a5SSteve French 	switch (ace->e_tag) {
287538c8a9a5SSteve French 	case ACL_USER:
287638c8a9a5SSteve French 		ace->e_uid = make_kuid(&init_user_ns,
287738c8a9a5SSteve French 				       le64_to_cpu(cifs_ace->cifs_uid));
287838c8a9a5SSteve French 		break;
287938c8a9a5SSteve French 	case ACL_GROUP:
288038c8a9a5SSteve French 		ace->e_gid = make_kgid(&init_user_ns,
288138c8a9a5SSteve French 				       le64_to_cpu(cifs_ace->cifs_uid));
288238c8a9a5SSteve French 		break;
288338c8a9a5SSteve French 	}
288438c8a9a5SSteve French 	return;
288538c8a9a5SSteve French }
288638c8a9a5SSteve French 
288738c8a9a5SSteve French /**
288838c8a9a5SSteve French  * cifs_to_posix_acl - copy cifs ACL format to POSIX ACL format
288938c8a9a5SSteve French  * @acl: ACLs returned in POSIX ACL format
289038c8a9a5SSteve French  * @src: ACLs in cifs format
289138c8a9a5SSteve French  * @acl_type: type of POSIX ACL requested
289238c8a9a5SSteve French  * @size_of_data_area: size of SMB we got
289338c8a9a5SSteve French  *
289438c8a9a5SSteve French  * This function converts ACLs from cifs format to POSIX ACL format.
289538c8a9a5SSteve French  * If @acl is NULL then the size of the buffer required to store POSIX ACLs in
289638c8a9a5SSteve French  * their uapi format is returned.
289738c8a9a5SSteve French  */
cifs_to_posix_acl(struct posix_acl ** acl,char * src,const int acl_type,const int size_of_data_area)289838c8a9a5SSteve French static int cifs_to_posix_acl(struct posix_acl **acl, char *src,
289938c8a9a5SSteve French 			     const int acl_type, const int size_of_data_area)
290038c8a9a5SSteve French {
290138c8a9a5SSteve French 	int size =  0;
290238c8a9a5SSteve French 	__u16 count;
290338c8a9a5SSteve French 	struct cifs_posix_ace *pACE;
290438c8a9a5SSteve French 	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
290538c8a9a5SSteve French 	struct posix_acl *kacl = NULL;
290638c8a9a5SSteve French 	struct posix_acl_entry *pa, *pe;
290738c8a9a5SSteve French 
290838c8a9a5SSteve French 	if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
290938c8a9a5SSteve French 		return -EOPNOTSUPP;
291038c8a9a5SSteve French 
291138c8a9a5SSteve French 	if (acl_type == ACL_TYPE_ACCESS) {
291238c8a9a5SSteve French 		count = le16_to_cpu(cifs_acl->access_entry_count);
291338c8a9a5SSteve French 		pACE = &cifs_acl->ace_array[0];
291438c8a9a5SSteve French 		size = sizeof(struct cifs_posix_acl);
291538c8a9a5SSteve French 		size += sizeof(struct cifs_posix_ace) * count;
291638c8a9a5SSteve French 		/* check if we would go beyond end of SMB */
291738c8a9a5SSteve French 		if (size_of_data_area < size) {
291838c8a9a5SSteve French 			cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
291938c8a9a5SSteve French 				 size_of_data_area, size);
292038c8a9a5SSteve French 			return -EINVAL;
292138c8a9a5SSteve French 		}
292238c8a9a5SSteve French 	} else if (acl_type == ACL_TYPE_DEFAULT) {
292338c8a9a5SSteve French 		count = le16_to_cpu(cifs_acl->access_entry_count);
292438c8a9a5SSteve French 		size = sizeof(struct cifs_posix_acl);
292538c8a9a5SSteve French 		size += sizeof(struct cifs_posix_ace) * count;
292638c8a9a5SSteve French 		/* skip past access ACEs to get to default ACEs */
292738c8a9a5SSteve French 		pACE = &cifs_acl->ace_array[count];
292838c8a9a5SSteve French 		count = le16_to_cpu(cifs_acl->default_entry_count);
292938c8a9a5SSteve French 		size += sizeof(struct cifs_posix_ace) * count;
293038c8a9a5SSteve French 		/* check if we would go beyond end of SMB */
293138c8a9a5SSteve French 		if (size_of_data_area < size)
293238c8a9a5SSteve French 			return -EINVAL;
293338c8a9a5SSteve French 	} else {
293438c8a9a5SSteve French 		/* illegal type */
293538c8a9a5SSteve French 		return -EINVAL;
293638c8a9a5SSteve French 	}
293738c8a9a5SSteve French 
293838c8a9a5SSteve French 	/* Allocate number of POSIX ACLs to store in VFS format. */
293938c8a9a5SSteve French 	kacl = posix_acl_alloc(count, GFP_NOFS);
294038c8a9a5SSteve French 	if (!kacl)
294138c8a9a5SSteve French 		return -ENOMEM;
294238c8a9a5SSteve French 
294338c8a9a5SSteve French 	FOREACH_ACL_ENTRY(pa, kacl, pe) {
294438c8a9a5SSteve French 		cifs_init_posix_acl(pa, pACE);
294538c8a9a5SSteve French 		pACE++;
294638c8a9a5SSteve French 	}
294738c8a9a5SSteve French 
294838c8a9a5SSteve French 	*acl = kacl;
294938c8a9a5SSteve French 	return 0;
295038c8a9a5SSteve French }
295138c8a9a5SSteve French 
295238c8a9a5SSteve French /**
295338c8a9a5SSteve French  * cifs_init_ace - convert ACL entry from POSIX ACL to cifs format
295438c8a9a5SSteve French  * @cifs_ace: the cifs ACL entry to store into
295538c8a9a5SSteve French  * @local_ace: the POSIX ACL entry to convert
295638c8a9a5SSteve French  */
cifs_init_ace(struct cifs_posix_ace * cifs_ace,const struct posix_acl_entry * local_ace)295738c8a9a5SSteve French static void cifs_init_ace(struct cifs_posix_ace *cifs_ace,
295838c8a9a5SSteve French 			  const struct posix_acl_entry *local_ace)
295938c8a9a5SSteve French {
296038c8a9a5SSteve French 	cifs_ace->cifs_e_perm = local_ace->e_perm;
296138c8a9a5SSteve French 	cifs_ace->cifs_e_tag =  local_ace->e_tag;
296238c8a9a5SSteve French 
296338c8a9a5SSteve French 	switch (local_ace->e_tag) {
296438c8a9a5SSteve French 	case ACL_USER:
296538c8a9a5SSteve French 		cifs_ace->cifs_uid =
296638c8a9a5SSteve French 			cpu_to_le64(from_kuid(&init_user_ns, local_ace->e_uid));
296738c8a9a5SSteve French 		break;
296838c8a9a5SSteve French 	case ACL_GROUP:
296938c8a9a5SSteve French 		cifs_ace->cifs_uid =
297038c8a9a5SSteve French 			cpu_to_le64(from_kgid(&init_user_ns, local_ace->e_gid));
297138c8a9a5SSteve French 		break;
297238c8a9a5SSteve French 	default:
297338c8a9a5SSteve French 		cifs_ace->cifs_uid = cpu_to_le64(-1);
297438c8a9a5SSteve French 	}
297538c8a9a5SSteve French }
297638c8a9a5SSteve French 
297738c8a9a5SSteve French /**
297838c8a9a5SSteve French  * posix_acl_to_cifs - convert ACLs from POSIX ACL to cifs format
297938c8a9a5SSteve French  * @parm_data: ACLs in cifs format to conver to
298038c8a9a5SSteve French  * @acl: ACLs in POSIX ACL format to convert from
298138c8a9a5SSteve French  * @acl_type: the type of POSIX ACLs stored in @acl
298238c8a9a5SSteve French  *
298338c8a9a5SSteve French  * Return: the number cifs ACL entries after conversion
298438c8a9a5SSteve French  */
posix_acl_to_cifs(char * parm_data,const struct posix_acl * acl,const int acl_type)298538c8a9a5SSteve French static __u16 posix_acl_to_cifs(char *parm_data, const struct posix_acl *acl,
298638c8a9a5SSteve French 			       const int acl_type)
298738c8a9a5SSteve French {
298838c8a9a5SSteve French 	__u16 rc = 0;
298938c8a9a5SSteve French 	struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
299038c8a9a5SSteve French 	const struct posix_acl_entry *pa, *pe;
299138c8a9a5SSteve French 	int count;
299238c8a9a5SSteve French 	int i = 0;
299338c8a9a5SSteve French 
299438c8a9a5SSteve French 	if ((acl == NULL) || (cifs_acl == NULL))
299538c8a9a5SSteve French 		return 0;
299638c8a9a5SSteve French 
299738c8a9a5SSteve French 	count = acl->a_count;
299838c8a9a5SSteve French 	cifs_dbg(FYI, "setting acl with %d entries\n", count);
299938c8a9a5SSteve French 
300038c8a9a5SSteve French 	/*
300138c8a9a5SSteve French 	 * Note that the uapi POSIX ACL version is verified by the VFS and is
300238c8a9a5SSteve French 	 * independent of the cifs ACL version. Changing the POSIX ACL version
300338c8a9a5SSteve French 	 * is a uapi change and if it's changed we will pass down the POSIX ACL
300438c8a9a5SSteve French 	 * version in struct posix_acl from the VFS. For now there's really
300538c8a9a5SSteve French 	 * only one that all filesystems know how to deal with.
300638c8a9a5SSteve French 	 */
300738c8a9a5SSteve French 	cifs_acl->version = cpu_to_le16(1);
300838c8a9a5SSteve French 	if (acl_type == ACL_TYPE_ACCESS) {
300938c8a9a5SSteve French 		cifs_acl->access_entry_count = cpu_to_le16(count);
301038c8a9a5SSteve French 		cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
301138c8a9a5SSteve French 	} else if (acl_type == ACL_TYPE_DEFAULT) {
301238c8a9a5SSteve French 		cifs_acl->default_entry_count = cpu_to_le16(count);
301338c8a9a5SSteve French 		cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
301438c8a9a5SSteve French 	} else {
301538c8a9a5SSteve French 		cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
301638c8a9a5SSteve French 		return 0;
301738c8a9a5SSteve French 	}
301838c8a9a5SSteve French 	FOREACH_ACL_ENTRY(pa, acl, pe) {
301938c8a9a5SSteve French 		cifs_init_ace(&cifs_acl->ace_array[i++], pa);
302038c8a9a5SSteve French 	}
302138c8a9a5SSteve French 	if (rc == 0) {
302238c8a9a5SSteve French 		rc = (__u16)(count * sizeof(struct cifs_posix_ace));
302338c8a9a5SSteve French 		rc += sizeof(struct cifs_posix_acl);
302438c8a9a5SSteve French 		/* BB add check to make sure ACL does not overflow SMB */
302538c8a9a5SSteve French 	}
302638c8a9a5SSteve French 	return rc;
302738c8a9a5SSteve French }
302838c8a9a5SSteve French 
cifs_do_get_acl(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,struct posix_acl ** acl,const int acl_type,const struct nls_table * nls_codepage,int remap)302938c8a9a5SSteve French int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
303038c8a9a5SSteve French 		    const unsigned char *searchName, struct posix_acl **acl,
303138c8a9a5SSteve French 		    const int acl_type, const struct nls_table *nls_codepage,
303238c8a9a5SSteve French 		    int remap)
303338c8a9a5SSteve French {
303438c8a9a5SSteve French /* SMB_QUERY_POSIX_ACL */
303538c8a9a5SSteve French 	TRANSACTION2_QPI_REQ *pSMB = NULL;
303638c8a9a5SSteve French 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
303738c8a9a5SSteve French 	int rc = 0;
303838c8a9a5SSteve French 	int bytes_returned;
303938c8a9a5SSteve French 	int name_len;
304038c8a9a5SSteve French 	__u16 params, byte_count;
304138c8a9a5SSteve French 
304238c8a9a5SSteve French 	cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
304338c8a9a5SSteve French 
304438c8a9a5SSteve French queryAclRetry:
304538c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
304638c8a9a5SSteve French 		(void **) &pSMBr);
304738c8a9a5SSteve French 	if (rc)
304838c8a9a5SSteve French 		return rc;
304938c8a9a5SSteve French 
305038c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
305138c8a9a5SSteve French 		name_len =
305238c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *) pSMB->FileName,
305338c8a9a5SSteve French 					   searchName, PATH_MAX, nls_codepage,
305438c8a9a5SSteve French 					   remap);
305538c8a9a5SSteve French 		name_len++;     /* trailing null */
305638c8a9a5SSteve French 		name_len *= 2;
305738c8a9a5SSteve French 		pSMB->FileName[name_len] = 0;
305838c8a9a5SSteve French 		pSMB->FileName[name_len+1] = 0;
305938c8a9a5SSteve French 	} else {
306038c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, searchName);
306138c8a9a5SSteve French 	}
306238c8a9a5SSteve French 
306338c8a9a5SSteve French 	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
306438c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
306538c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
306638c8a9a5SSteve French 	/* BB find exact max data count below from sess structure BB */
306738c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(4000);
306838c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
306938c8a9a5SSteve French 	pSMB->Reserved = 0;
307038c8a9a5SSteve French 	pSMB->Flags = 0;
307138c8a9a5SSteve French 	pSMB->Timeout = 0;
307238c8a9a5SSteve French 	pSMB->Reserved2 = 0;
307338c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(
307438c8a9a5SSteve French 		offsetof(struct smb_com_transaction2_qpi_req,
307538c8a9a5SSteve French 			 InformationLevel) - 4);
307638c8a9a5SSteve French 	pSMB->DataCount = 0;
307738c8a9a5SSteve French 	pSMB->DataOffset = 0;
307838c8a9a5SSteve French 	pSMB->SetupCount = 1;
307938c8a9a5SSteve French 	pSMB->Reserved3 = 0;
308038c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
308138c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
308238c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
308338c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
308438c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
308538c8a9a5SSteve French 	pSMB->Reserved4 = 0;
308638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
308738c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
308838c8a9a5SSteve French 
308938c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
309038c8a9a5SSteve French 		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
309138c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
309238c8a9a5SSteve French 	if (rc) {
309338c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
309438c8a9a5SSteve French 	} else {
309538c8a9a5SSteve French 		/* decode response */
309638c8a9a5SSteve French 
309738c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
309838c8a9a5SSteve French 		/* BB also check enough total bytes returned */
309938c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 2)
310038c8a9a5SSteve French 			rc = -EIO;      /* bad smb */
310138c8a9a5SSteve French 		else {
310238c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
310338c8a9a5SSteve French 			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
310438c8a9a5SSteve French 			rc = cifs_to_posix_acl(acl,
310538c8a9a5SSteve French 				(char *)&pSMBr->hdr.Protocol+data_offset,
310638c8a9a5SSteve French 				acl_type, count);
310738c8a9a5SSteve French 		}
310838c8a9a5SSteve French 	}
310938c8a9a5SSteve French 	cifs_buf_release(pSMB);
311038c8a9a5SSteve French 	/*
311138c8a9a5SSteve French 	 * The else branch after SendReceive() doesn't return EAGAIN so if we
311238c8a9a5SSteve French 	 * allocated @acl in cifs_to_posix_acl() we are guaranteed to return
311338c8a9a5SSteve French 	 * here and don't leak POSIX ACLs.
311438c8a9a5SSteve French 	 */
311538c8a9a5SSteve French 	if (rc == -EAGAIN)
311638c8a9a5SSteve French 		goto queryAclRetry;
311738c8a9a5SSteve French 	return rc;
311838c8a9a5SSteve French }
311938c8a9a5SSteve French 
cifs_do_set_acl(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * fileName,const struct posix_acl * acl,const int acl_type,const struct nls_table * nls_codepage,int remap)312038c8a9a5SSteve French int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
312138c8a9a5SSteve French 		    const unsigned char *fileName, const struct posix_acl *acl,
312238c8a9a5SSteve French 		    const int acl_type, const struct nls_table *nls_codepage,
312338c8a9a5SSteve French 		    int remap)
312438c8a9a5SSteve French {
312538c8a9a5SSteve French 	struct smb_com_transaction2_spi_req *pSMB = NULL;
312638c8a9a5SSteve French 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
312738c8a9a5SSteve French 	char *parm_data;
312838c8a9a5SSteve French 	int name_len;
312938c8a9a5SSteve French 	int rc = 0;
313038c8a9a5SSteve French 	int bytes_returned = 0;
313138c8a9a5SSteve French 	__u16 params, byte_count, data_count, param_offset, offset;
313238c8a9a5SSteve French 
313338c8a9a5SSteve French 	cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
313438c8a9a5SSteve French setAclRetry:
313538c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
313638c8a9a5SSteve French 		      (void **) &pSMBr);
313738c8a9a5SSteve French 	if (rc)
313838c8a9a5SSteve French 		return rc;
313938c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
314038c8a9a5SSteve French 		name_len =
314138c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
314238c8a9a5SSteve French 					   PATH_MAX, nls_codepage, remap);
314338c8a9a5SSteve French 		name_len++;     /* trailing null */
314438c8a9a5SSteve French 		name_len *= 2;
314538c8a9a5SSteve French 	} else {
314638c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, fileName);
314738c8a9a5SSteve French 	}
314838c8a9a5SSteve French 	params = 6 + name_len;
314938c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
315038c8a9a5SSteve French 	/* BB find max SMB size from sess */
315138c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
315238c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
315338c8a9a5SSteve French 	pSMB->Reserved = 0;
315438c8a9a5SSteve French 	pSMB->Flags = 0;
315538c8a9a5SSteve French 	pSMB->Timeout = 0;
315638c8a9a5SSteve French 	pSMB->Reserved2 = 0;
315738c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
315838c8a9a5SSteve French 				InformationLevel) - 4;
315938c8a9a5SSteve French 	offset = param_offset + params;
3160f1f047bdSGustavo A. R. Silva 	parm_data = ((char *)pSMB) + sizeof(pSMB->hdr.smb_buf_length) + offset;
316138c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
316238c8a9a5SSteve French 
316338c8a9a5SSteve French 	/* convert to on the wire format for POSIX ACL */
316438c8a9a5SSteve French 	data_count = posix_acl_to_cifs(parm_data, acl, acl_type);
316538c8a9a5SSteve French 
316638c8a9a5SSteve French 	if (data_count == 0) {
316738c8a9a5SSteve French 		rc = -EOPNOTSUPP;
316838c8a9a5SSteve French 		goto setACLerrorExit;
316938c8a9a5SSteve French 	}
317038c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
317138c8a9a5SSteve French 	pSMB->SetupCount = 1;
317238c8a9a5SSteve French 	pSMB->Reserved3 = 0;
317338c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
317438c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
317538c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + data_count;
317638c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(data_count);
317738c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
317838c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
317938c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
318038c8a9a5SSteve French 	pSMB->Reserved4 = 0;
318138c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
318238c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
318338c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
318438c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
318538c8a9a5SSteve French 	if (rc)
318638c8a9a5SSteve French 		cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
318738c8a9a5SSteve French 
318838c8a9a5SSteve French setACLerrorExit:
318938c8a9a5SSteve French 	cifs_buf_release(pSMB);
319038c8a9a5SSteve French 	if (rc == -EAGAIN)
319138c8a9a5SSteve French 		goto setAclRetry;
319238c8a9a5SSteve French 	return rc;
319338c8a9a5SSteve French }
319438c8a9a5SSteve French #else
cifs_do_get_acl(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,struct posix_acl ** acl,const int acl_type,const struct nls_table * nls_codepage,int remap)319538c8a9a5SSteve French int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon,
319638c8a9a5SSteve French 		    const unsigned char *searchName, struct posix_acl **acl,
319738c8a9a5SSteve French 		    const int acl_type, const struct nls_table *nls_codepage,
319838c8a9a5SSteve French 		    int remap)
319938c8a9a5SSteve French {
320038c8a9a5SSteve French 	return -EOPNOTSUPP;
320138c8a9a5SSteve French }
320238c8a9a5SSteve French 
cifs_do_set_acl(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * fileName,const struct posix_acl * acl,const int acl_type,const struct nls_table * nls_codepage,int remap)320338c8a9a5SSteve French int cifs_do_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
320438c8a9a5SSteve French 		    const unsigned char *fileName, const struct posix_acl *acl,
320538c8a9a5SSteve French 		    const int acl_type, const struct nls_table *nls_codepage,
320638c8a9a5SSteve French 		    int remap)
320738c8a9a5SSteve French {
320838c8a9a5SSteve French 	return -EOPNOTSUPP;
320938c8a9a5SSteve French }
321038c8a9a5SSteve French #endif /* CONFIG_FS_POSIX_ACL */
321138c8a9a5SSteve French 
321238c8a9a5SSteve French int
CIFSGetExtAttr(const unsigned int xid,struct cifs_tcon * tcon,const int netfid,__u64 * pExtAttrBits,__u64 * pMask)321338c8a9a5SSteve French CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
321438c8a9a5SSteve French 	       const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
321538c8a9a5SSteve French {
321638c8a9a5SSteve French 	int rc = 0;
321738c8a9a5SSteve French 	struct smb_t2_qfi_req *pSMB = NULL;
321838c8a9a5SSteve French 	struct smb_t2_qfi_rsp *pSMBr = NULL;
321938c8a9a5SSteve French 	int bytes_returned;
322038c8a9a5SSteve French 	__u16 params, byte_count;
322138c8a9a5SSteve French 
322238c8a9a5SSteve French 	cifs_dbg(FYI, "In GetExtAttr\n");
322338c8a9a5SSteve French 	if (tcon == NULL)
322438c8a9a5SSteve French 		return -ENODEV;
322538c8a9a5SSteve French 
322638c8a9a5SSteve French GetExtAttrRetry:
322738c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
322838c8a9a5SSteve French 		      (void **) &pSMBr);
322938c8a9a5SSteve French 	if (rc)
323038c8a9a5SSteve French 		return rc;
323138c8a9a5SSteve French 
323238c8a9a5SSteve French 	params = 2 /* level */ + 2 /* fid */;
323338c8a9a5SSteve French 	pSMB->t2.TotalDataCount = 0;
323438c8a9a5SSteve French 	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
323538c8a9a5SSteve French 	/* BB find exact max data count below from sess structure BB */
323638c8a9a5SSteve French 	pSMB->t2.MaxDataCount = cpu_to_le16(4000);
323738c8a9a5SSteve French 	pSMB->t2.MaxSetupCount = 0;
323838c8a9a5SSteve French 	pSMB->t2.Reserved = 0;
323938c8a9a5SSteve French 	pSMB->t2.Flags = 0;
324038c8a9a5SSteve French 	pSMB->t2.Timeout = 0;
324138c8a9a5SSteve French 	pSMB->t2.Reserved2 = 0;
324238c8a9a5SSteve French 	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
324338c8a9a5SSteve French 					       Fid) - 4);
324438c8a9a5SSteve French 	pSMB->t2.DataCount = 0;
324538c8a9a5SSteve French 	pSMB->t2.DataOffset = 0;
324638c8a9a5SSteve French 	pSMB->t2.SetupCount = 1;
324738c8a9a5SSteve French 	pSMB->t2.Reserved3 = 0;
324838c8a9a5SSteve French 	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
324938c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
325038c8a9a5SSteve French 	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
325138c8a9a5SSteve French 	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
325238c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
325338c8a9a5SSteve French 	pSMB->Pad = 0;
325438c8a9a5SSteve French 	pSMB->Fid = netfid;
325538c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
325638c8a9a5SSteve French 	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
325738c8a9a5SSteve French 
325838c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
325938c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
326038c8a9a5SSteve French 	if (rc) {
326138c8a9a5SSteve French 		cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
326238c8a9a5SSteve French 	} else {
326338c8a9a5SSteve French 		/* decode response */
326438c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
326538c8a9a5SSteve French 		/* BB also check enough total bytes returned */
326638c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 2)
326738c8a9a5SSteve French 			/* If rc should we check for EOPNOSUPP and
326838c8a9a5SSteve French 			   disable the srvino flag? or in caller? */
326938c8a9a5SSteve French 			rc = -EIO;      /* bad smb */
327038c8a9a5SSteve French 		else {
327138c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
327238c8a9a5SSteve French 			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
327338c8a9a5SSteve French 			struct file_chattr_info *pfinfo;
327438c8a9a5SSteve French 
327538c8a9a5SSteve French 			if (count != 16) {
327638c8a9a5SSteve French 				cifs_dbg(FYI, "Invalid size ret in GetExtAttr\n");
327738c8a9a5SSteve French 				rc = -EIO;
327838c8a9a5SSteve French 				goto GetExtAttrOut;
327938c8a9a5SSteve French 			}
328038c8a9a5SSteve French 			pfinfo = (struct file_chattr_info *)
328138c8a9a5SSteve French 				 (data_offset + (char *) &pSMBr->hdr.Protocol);
328238c8a9a5SSteve French 			*pExtAttrBits = le64_to_cpu(pfinfo->mode);
328338c8a9a5SSteve French 			*pMask = le64_to_cpu(pfinfo->mask);
328438c8a9a5SSteve French 		}
328538c8a9a5SSteve French 	}
328638c8a9a5SSteve French GetExtAttrOut:
328738c8a9a5SSteve French 	cifs_buf_release(pSMB);
328838c8a9a5SSteve French 	if (rc == -EAGAIN)
328938c8a9a5SSteve French 		goto GetExtAttrRetry;
329038c8a9a5SSteve French 	return rc;
329138c8a9a5SSteve French }
329238c8a9a5SSteve French 
329338c8a9a5SSteve French #endif /* CONFIG_POSIX */
329438c8a9a5SSteve French 
329538c8a9a5SSteve French /*
329638c8a9a5SSteve French  * Initialize NT TRANSACT SMB into small smb request buffer.  This assumes that
329738c8a9a5SSteve French  * all NT TRANSACTS that we init here have total parm and data under about 400
329838c8a9a5SSteve French  * bytes (to fit in small cifs buffer size), which is the case so far, it
329938c8a9a5SSteve French  * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
330038c8a9a5SSteve French  * returned setup area) and MaxParameterCount (returned parms size) must be set
330138c8a9a5SSteve French  * by caller
330238c8a9a5SSteve French  */
330338c8a9a5SSteve French static int
smb_init_nttransact(const __u16 sub_command,const int setup_count,const int parm_len,struct cifs_tcon * tcon,void ** ret_buf)330438c8a9a5SSteve French smb_init_nttransact(const __u16 sub_command, const int setup_count,
330538c8a9a5SSteve French 		   const int parm_len, struct cifs_tcon *tcon,
330638c8a9a5SSteve French 		   void **ret_buf)
330738c8a9a5SSteve French {
330838c8a9a5SSteve French 	int rc;
330938c8a9a5SSteve French 	__u32 temp_offset;
331038c8a9a5SSteve French 	struct smb_com_ntransact_req *pSMB;
331138c8a9a5SSteve French 
331238c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
331338c8a9a5SSteve French 				(void **)&pSMB);
331438c8a9a5SSteve French 	if (rc)
331538c8a9a5SSteve French 		return rc;
331638c8a9a5SSteve French 	*ret_buf = (void *)pSMB;
331738c8a9a5SSteve French 	pSMB->Reserved = 0;
331838c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le32(parm_len);
331938c8a9a5SSteve French 	pSMB->TotalDataCount  = 0;
332038c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
332138c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
332238c8a9a5SSteve French 	pSMB->DataCount  = pSMB->TotalDataCount;
332338c8a9a5SSteve French 	temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
332438c8a9a5SSteve French 			(setup_count * 2) - 4 /* for rfc1001 length itself */;
332538c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le32(temp_offset);
332638c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
332738c8a9a5SSteve French 	pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
332838c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(sub_command);
332938c8a9a5SSteve French 	return 0;
333038c8a9a5SSteve French }
333138c8a9a5SSteve French 
333238c8a9a5SSteve French static int
validate_ntransact(char * buf,char ** ppparm,char ** ppdata,__u32 * pparmlen,__u32 * pdatalen)333338c8a9a5SSteve French validate_ntransact(char *buf, char **ppparm, char **ppdata,
333438c8a9a5SSteve French 		   __u32 *pparmlen, __u32 *pdatalen)
333538c8a9a5SSteve French {
333638c8a9a5SSteve French 	char *end_of_smb;
333738c8a9a5SSteve French 	__u32 data_count, data_offset, parm_count, parm_offset;
333838c8a9a5SSteve French 	struct smb_com_ntransact_rsp *pSMBr;
333938c8a9a5SSteve French 	u16 bcc;
334038c8a9a5SSteve French 
334138c8a9a5SSteve French 	*pdatalen = 0;
334238c8a9a5SSteve French 	*pparmlen = 0;
334338c8a9a5SSteve French 
334438c8a9a5SSteve French 	if (buf == NULL)
334538c8a9a5SSteve French 		return -EINVAL;
334638c8a9a5SSteve French 
334738c8a9a5SSteve French 	pSMBr = (struct smb_com_ntransact_rsp *)buf;
334838c8a9a5SSteve French 
334938c8a9a5SSteve French 	bcc = get_bcc(&pSMBr->hdr);
335038c8a9a5SSteve French 	end_of_smb = 2 /* sizeof byte count */ + bcc +
335138c8a9a5SSteve French 			(char *)&pSMBr->ByteCount;
335238c8a9a5SSteve French 
335338c8a9a5SSteve French 	data_offset = le32_to_cpu(pSMBr->DataOffset);
335438c8a9a5SSteve French 	data_count = le32_to_cpu(pSMBr->DataCount);
335538c8a9a5SSteve French 	parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
335638c8a9a5SSteve French 	parm_count = le32_to_cpu(pSMBr->ParameterCount);
335738c8a9a5SSteve French 
335838c8a9a5SSteve French 	*ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
335938c8a9a5SSteve French 	*ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
336038c8a9a5SSteve French 
336138c8a9a5SSteve French 	/* should we also check that parm and data areas do not overlap? */
336238c8a9a5SSteve French 	if (*ppparm > end_of_smb) {
336338c8a9a5SSteve French 		cifs_dbg(FYI, "parms start after end of smb\n");
336438c8a9a5SSteve French 		return -EINVAL;
336538c8a9a5SSteve French 	} else if (parm_count + *ppparm > end_of_smb) {
336638c8a9a5SSteve French 		cifs_dbg(FYI, "parm end after end of smb\n");
336738c8a9a5SSteve French 		return -EINVAL;
336838c8a9a5SSteve French 	} else if (*ppdata > end_of_smb) {
336938c8a9a5SSteve French 		cifs_dbg(FYI, "data starts after end of smb\n");
337038c8a9a5SSteve French 		return -EINVAL;
337138c8a9a5SSteve French 	} else if (data_count + *ppdata > end_of_smb) {
337238c8a9a5SSteve French 		cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
337338c8a9a5SSteve French 			 *ppdata, data_count, (data_count + *ppdata),
337438c8a9a5SSteve French 			 end_of_smb, pSMBr);
337538c8a9a5SSteve French 		return -EINVAL;
337638c8a9a5SSteve French 	} else if (parm_count + data_count > bcc) {
337738c8a9a5SSteve French 		cifs_dbg(FYI, "parm count and data count larger than SMB\n");
337838c8a9a5SSteve French 		return -EINVAL;
337938c8a9a5SSteve French 	}
338038c8a9a5SSteve French 	*pdatalen = data_count;
338138c8a9a5SSteve French 	*pparmlen = parm_count;
338238c8a9a5SSteve French 	return 0;
338338c8a9a5SSteve French }
338438c8a9a5SSteve French 
338538c8a9a5SSteve French /* Get Security Descriptor (by handle) from remote server for a file or dir */
338638c8a9a5SSteve French int
CIFSSMBGetCIFSACL(const unsigned int xid,struct cifs_tcon * tcon,__u16 fid,struct cifs_ntsd ** acl_inf,__u32 * pbuflen)338738c8a9a5SSteve French CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
338838c8a9a5SSteve French 		  struct cifs_ntsd **acl_inf, __u32 *pbuflen)
338938c8a9a5SSteve French {
339038c8a9a5SSteve French 	int rc = 0;
339138c8a9a5SSteve French 	int buf_type = 0;
339238c8a9a5SSteve French 	QUERY_SEC_DESC_REQ *pSMB;
339338c8a9a5SSteve French 	struct kvec iov[1];
339438c8a9a5SSteve French 	struct kvec rsp_iov;
339538c8a9a5SSteve French 
339638c8a9a5SSteve French 	cifs_dbg(FYI, "GetCifsACL\n");
339738c8a9a5SSteve French 
339838c8a9a5SSteve French 	*pbuflen = 0;
339938c8a9a5SSteve French 	*acl_inf = NULL;
340038c8a9a5SSteve French 
340138c8a9a5SSteve French 	rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
340238c8a9a5SSteve French 			8 /* parm len */, tcon, (void **) &pSMB);
340338c8a9a5SSteve French 	if (rc)
340438c8a9a5SSteve French 		return rc;
340538c8a9a5SSteve French 
340638c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le32(4);
340738c8a9a5SSteve French 	/* BB TEST with big acls that might need to be e.g. larger than 16K */
340838c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
340938c8a9a5SSteve French 	pSMB->Fid = fid; /* file handle always le */
341038c8a9a5SSteve French 	pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
341138c8a9a5SSteve French 				     CIFS_ACL_DACL);
341238c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
341338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, 11);
341438c8a9a5SSteve French 	iov[0].iov_base = (char *)pSMB;
341538c8a9a5SSteve French 	iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
341638c8a9a5SSteve French 
341738c8a9a5SSteve French 	rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
341838c8a9a5SSteve French 			  0, &rsp_iov);
341938c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
342038c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
342138c8a9a5SSteve French 	if (rc) {
342238c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
342338c8a9a5SSteve French 	} else {                /* decode response */
342438c8a9a5SSteve French 		__le32 *parm;
342538c8a9a5SSteve French 		__u32 parm_len;
342638c8a9a5SSteve French 		__u32 acl_len;
342738c8a9a5SSteve French 		struct smb_com_ntransact_rsp *pSMBr;
342838c8a9a5SSteve French 		char *pdata;
342938c8a9a5SSteve French 
343038c8a9a5SSteve French /* validate_nttransact */
343138c8a9a5SSteve French 		rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
343238c8a9a5SSteve French 					&pdata, &parm_len, pbuflen);
343338c8a9a5SSteve French 		if (rc)
343438c8a9a5SSteve French 			goto qsec_out;
343538c8a9a5SSteve French 		pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
343638c8a9a5SSteve French 
343738c8a9a5SSteve French 		cifs_dbg(FYI, "smb %p parm %p data %p\n",
343838c8a9a5SSteve French 			 pSMBr, parm, *acl_inf);
343938c8a9a5SSteve French 
344038c8a9a5SSteve French 		if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
344138c8a9a5SSteve French 			rc = -EIO;      /* bad smb */
344238c8a9a5SSteve French 			*pbuflen = 0;
344338c8a9a5SSteve French 			goto qsec_out;
344438c8a9a5SSteve French 		}
344538c8a9a5SSteve French 
344638c8a9a5SSteve French /* BB check that data area is minimum length and as big as acl_len */
344738c8a9a5SSteve French 
344838c8a9a5SSteve French 		acl_len = le32_to_cpu(*parm);
344938c8a9a5SSteve French 		if (acl_len != *pbuflen) {
345038c8a9a5SSteve French 			cifs_dbg(VFS, "acl length %d does not match %d\n",
345138c8a9a5SSteve French 				 acl_len, *pbuflen);
345238c8a9a5SSteve French 			if (*pbuflen > acl_len)
345338c8a9a5SSteve French 				*pbuflen = acl_len;
345438c8a9a5SSteve French 		}
345538c8a9a5SSteve French 
345638c8a9a5SSteve French 		/* check if buffer is big enough for the acl
345738c8a9a5SSteve French 		   header followed by the smallest SID */
345838c8a9a5SSteve French 		if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
345938c8a9a5SSteve French 		    (*pbuflen >= 64 * 1024)) {
346038c8a9a5SSteve French 			cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
346138c8a9a5SSteve French 			rc = -EINVAL;
346238c8a9a5SSteve French 			*pbuflen = 0;
346338c8a9a5SSteve French 		} else {
346438c8a9a5SSteve French 			*acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
346538c8a9a5SSteve French 			if (*acl_inf == NULL) {
346638c8a9a5SSteve French 				*pbuflen = 0;
346738c8a9a5SSteve French 				rc = -ENOMEM;
346838c8a9a5SSteve French 			}
346938c8a9a5SSteve French 		}
347038c8a9a5SSteve French 	}
347138c8a9a5SSteve French qsec_out:
347238c8a9a5SSteve French 	free_rsp_buf(buf_type, rsp_iov.iov_base);
347338c8a9a5SSteve French 	return rc;
347438c8a9a5SSteve French }
347538c8a9a5SSteve French 
347638c8a9a5SSteve French int
CIFSSMBSetCIFSACL(const unsigned int xid,struct cifs_tcon * tcon,__u16 fid,struct cifs_ntsd * pntsd,__u32 acllen,int aclflag)347738c8a9a5SSteve French CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
347838c8a9a5SSteve French 			struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
347938c8a9a5SSteve French {
348038c8a9a5SSteve French 	__u16 byte_count, param_count, data_count, param_offset, data_offset;
348138c8a9a5SSteve French 	int rc = 0;
348238c8a9a5SSteve French 	int bytes_returned = 0;
348338c8a9a5SSteve French 	SET_SEC_DESC_REQ *pSMB = NULL;
348438c8a9a5SSteve French 	void *pSMBr;
348538c8a9a5SSteve French 
348638c8a9a5SSteve French setCifsAclRetry:
348738c8a9a5SSteve French 	rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
348838c8a9a5SSteve French 	if (rc)
348938c8a9a5SSteve French 		return rc;
349038c8a9a5SSteve French 
349138c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
349238c8a9a5SSteve French 	pSMB->Reserved = 0;
349338c8a9a5SSteve French 
349438c8a9a5SSteve French 	param_count = 8;
349538c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
349638c8a9a5SSteve French 	data_count = acllen;
349738c8a9a5SSteve French 	data_offset = param_offset + param_count;
349838c8a9a5SSteve French 	byte_count = 3 /* pad */  + param_count;
349938c8a9a5SSteve French 
350038c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le32(data_count);
350138c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
350238c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le32(4);
350338c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le32(16384);
350438c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le32(param_count);
350538c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le32(param_offset);
350638c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
350738c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le32(data_offset);
350838c8a9a5SSteve French 	pSMB->SetupCount = 0;
350938c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
351038c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
351138c8a9a5SSteve French 
351238c8a9a5SSteve French 	pSMB->Fid = fid; /* file handle always le */
351338c8a9a5SSteve French 	pSMB->Reserved2 = 0;
351438c8a9a5SSteve French 	pSMB->AclFlags = cpu_to_le32(aclflag);
351538c8a9a5SSteve French 
351638c8a9a5SSteve French 	if (pntsd && acllen) {
351738c8a9a5SSteve French 		memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
351838c8a9a5SSteve French 				data_offset, pntsd, acllen);
351938c8a9a5SSteve French 		inc_rfc1001_len(pSMB, byte_count + data_count);
352038c8a9a5SSteve French 	} else
352138c8a9a5SSteve French 		inc_rfc1001_len(pSMB, byte_count);
352238c8a9a5SSteve French 
352338c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
352438c8a9a5SSteve French 		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
352538c8a9a5SSteve French 
352638c8a9a5SSteve French 	cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
352738c8a9a5SSteve French 		 bytes_returned, rc);
352838c8a9a5SSteve French 	if (rc)
352938c8a9a5SSteve French 		cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
353038c8a9a5SSteve French 	cifs_buf_release(pSMB);
353138c8a9a5SSteve French 
353238c8a9a5SSteve French 	if (rc == -EAGAIN)
353338c8a9a5SSteve French 		goto setCifsAclRetry;
353438c8a9a5SSteve French 
353538c8a9a5SSteve French 	return (rc);
353638c8a9a5SSteve French }
353738c8a9a5SSteve French 
353838c8a9a5SSteve French 
353938c8a9a5SSteve French /* Legacy Query Path Information call for lookup to old servers such
354038c8a9a5SSteve French    as Win9x/WinME */
354138c8a9a5SSteve French 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)354238c8a9a5SSteve French SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
354338c8a9a5SSteve French 		    const char *search_name, FILE_ALL_INFO *data,
354438c8a9a5SSteve French 		    const struct nls_table *nls_codepage, int remap)
354538c8a9a5SSteve French {
354638c8a9a5SSteve French 	QUERY_INFORMATION_REQ *pSMB;
354738c8a9a5SSteve French 	QUERY_INFORMATION_RSP *pSMBr;
354838c8a9a5SSteve French 	int rc = 0;
354938c8a9a5SSteve French 	int bytes_returned;
355038c8a9a5SSteve French 	int name_len;
355138c8a9a5SSteve French 
355238c8a9a5SSteve French 	cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
355338c8a9a5SSteve French QInfRetry:
355438c8a9a5SSteve French 	rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
355538c8a9a5SSteve French 		      (void **) &pSMBr);
355638c8a9a5SSteve French 	if (rc)
355738c8a9a5SSteve French 		return rc;
355838c8a9a5SSteve French 
355938c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
356038c8a9a5SSteve French 		name_len =
356138c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *) pSMB->FileName,
356238c8a9a5SSteve French 					   search_name, PATH_MAX, nls_codepage,
356338c8a9a5SSteve French 					   remap);
356438c8a9a5SSteve French 		name_len++;     /* trailing null */
356538c8a9a5SSteve French 		name_len *= 2;
356638c8a9a5SSteve French 	} else {
356738c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, search_name);
356838c8a9a5SSteve French 	}
356938c8a9a5SSteve French 	pSMB->BufferFormat = 0x04;
357038c8a9a5SSteve French 	name_len++; /* account for buffer type byte */
357138c8a9a5SSteve French 	inc_rfc1001_len(pSMB, (__u16)name_len);
357238c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(name_len);
357338c8a9a5SSteve French 
357438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
357538c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
357638c8a9a5SSteve French 	if (rc) {
357738c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
357838c8a9a5SSteve French 	} else if (data) {
357938c8a9a5SSteve French 		struct timespec64 ts;
358038c8a9a5SSteve French 		__u32 time = le32_to_cpu(pSMBr->last_write_time);
358138c8a9a5SSteve French 
358238c8a9a5SSteve French 		/* decode response */
358338c8a9a5SSteve French 		/* BB FIXME - add time zone adjustment BB */
358438c8a9a5SSteve French 		memset(data, 0, sizeof(FILE_ALL_INFO));
358538c8a9a5SSteve French 		ts.tv_nsec = 0;
358638c8a9a5SSteve French 		ts.tv_sec = time;
358738c8a9a5SSteve French 		/* decode time fields */
358838c8a9a5SSteve French 		data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
358938c8a9a5SSteve French 		data->LastWriteTime = data->ChangeTime;
359038c8a9a5SSteve French 		data->LastAccessTime = 0;
359138c8a9a5SSteve French 		data->AllocationSize =
359238c8a9a5SSteve French 			cpu_to_le64(le32_to_cpu(pSMBr->size));
359338c8a9a5SSteve French 		data->EndOfFile = data->AllocationSize;
359438c8a9a5SSteve French 		data->Attributes =
359538c8a9a5SSteve French 			cpu_to_le32(le16_to_cpu(pSMBr->attr));
359638c8a9a5SSteve French 	} else
359738c8a9a5SSteve French 		rc = -EIO; /* bad buffer passed in */
359838c8a9a5SSteve French 
359938c8a9a5SSteve French 	cifs_buf_release(pSMB);
360038c8a9a5SSteve French 
360138c8a9a5SSteve French 	if (rc == -EAGAIN)
360238c8a9a5SSteve French 		goto QInfRetry;
360338c8a9a5SSteve French 
360438c8a9a5SSteve French 	return rc;
360538c8a9a5SSteve French }
360638c8a9a5SSteve French 
360738c8a9a5SSteve French int
CIFSSMBQFileInfo(const unsigned int xid,struct cifs_tcon * tcon,u16 netfid,FILE_ALL_INFO * pFindData)360838c8a9a5SSteve French CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
360938c8a9a5SSteve French 		 u16 netfid, FILE_ALL_INFO *pFindData)
361038c8a9a5SSteve French {
361138c8a9a5SSteve French 	struct smb_t2_qfi_req *pSMB = NULL;
361238c8a9a5SSteve French 	struct smb_t2_qfi_rsp *pSMBr = NULL;
361338c8a9a5SSteve French 	int rc = 0;
361438c8a9a5SSteve French 	int bytes_returned;
361538c8a9a5SSteve French 	__u16 params, byte_count;
361638c8a9a5SSteve French 
361738c8a9a5SSteve French QFileInfoRetry:
361838c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
361938c8a9a5SSteve French 		      (void **) &pSMBr);
362038c8a9a5SSteve French 	if (rc)
362138c8a9a5SSteve French 		return rc;
362238c8a9a5SSteve French 
362338c8a9a5SSteve French 	params = 2 /* level */ + 2 /* fid */;
362438c8a9a5SSteve French 	pSMB->t2.TotalDataCount = 0;
362538c8a9a5SSteve French 	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
362638c8a9a5SSteve French 	/* BB find exact max data count below from sess structure BB */
362738c8a9a5SSteve French 	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
362838c8a9a5SSteve French 	pSMB->t2.MaxSetupCount = 0;
362938c8a9a5SSteve French 	pSMB->t2.Reserved = 0;
363038c8a9a5SSteve French 	pSMB->t2.Flags = 0;
363138c8a9a5SSteve French 	pSMB->t2.Timeout = 0;
363238c8a9a5SSteve French 	pSMB->t2.Reserved2 = 0;
363338c8a9a5SSteve French 	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
363438c8a9a5SSteve French 					       Fid) - 4);
363538c8a9a5SSteve French 	pSMB->t2.DataCount = 0;
363638c8a9a5SSteve French 	pSMB->t2.DataOffset = 0;
363738c8a9a5SSteve French 	pSMB->t2.SetupCount = 1;
363838c8a9a5SSteve French 	pSMB->t2.Reserved3 = 0;
363938c8a9a5SSteve French 	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
364038c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
364138c8a9a5SSteve French 	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
364238c8a9a5SSteve French 	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
364338c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
364438c8a9a5SSteve French 	pSMB->Pad = 0;
364538c8a9a5SSteve French 	pSMB->Fid = netfid;
364638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
364738c8a9a5SSteve French 	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
364838c8a9a5SSteve French 
364938c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
365038c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
365138c8a9a5SSteve French 	if (rc) {
365238c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QFileInfo = %d\n", rc);
365338c8a9a5SSteve French 	} else {		/* decode response */
365438c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
365538c8a9a5SSteve French 
365638c8a9a5SSteve French 		if (rc) /* BB add auto retry on EOPNOTSUPP? */
365738c8a9a5SSteve French 			rc = -EIO;
365838c8a9a5SSteve French 		else if (get_bcc(&pSMBr->hdr) < 40)
365938c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
366038c8a9a5SSteve French 		else if (pFindData) {
366138c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
366238c8a9a5SSteve French 			memcpy((char *) pFindData,
366338c8a9a5SSteve French 			       (char *) &pSMBr->hdr.Protocol +
366438c8a9a5SSteve French 			       data_offset, sizeof(FILE_ALL_INFO));
366538c8a9a5SSteve French 		} else
366638c8a9a5SSteve French 		    rc = -ENOMEM;
366738c8a9a5SSteve French 	}
366838c8a9a5SSteve French 	cifs_buf_release(pSMB);
366938c8a9a5SSteve French 	if (rc == -EAGAIN)
367038c8a9a5SSteve French 		goto QFileInfoRetry;
367138c8a9a5SSteve French 
367238c8a9a5SSteve French 	return rc;
367338c8a9a5SSteve French }
367438c8a9a5SSteve French 
367538c8a9a5SSteve French int
CIFSSMBQPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const char * search_name,FILE_ALL_INFO * data,int legacy,const struct nls_table * nls_codepage,int remap)367638c8a9a5SSteve French CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
367738c8a9a5SSteve French 		 const char *search_name, FILE_ALL_INFO *data,
367838c8a9a5SSteve French 		 int legacy /* old style infolevel */,
367938c8a9a5SSteve French 		 const struct nls_table *nls_codepage, int remap)
368038c8a9a5SSteve French {
368138c8a9a5SSteve French 	/* level 263 SMB_QUERY_FILE_ALL_INFO */
368238c8a9a5SSteve French 	TRANSACTION2_QPI_REQ *pSMB = NULL;
368338c8a9a5SSteve French 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
368438c8a9a5SSteve French 	int rc = 0;
368538c8a9a5SSteve French 	int bytes_returned;
368638c8a9a5SSteve French 	int name_len;
368738c8a9a5SSteve French 	__u16 params, byte_count;
368838c8a9a5SSteve French 
368938c8a9a5SSteve French 	/* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
369038c8a9a5SSteve French QPathInfoRetry:
369138c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
369238c8a9a5SSteve French 		      (void **) &pSMBr);
369338c8a9a5SSteve French 	if (rc)
369438c8a9a5SSteve French 		return rc;
369538c8a9a5SSteve French 
369638c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
369738c8a9a5SSteve French 		name_len =
369838c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
369938c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
370038c8a9a5SSteve French 		name_len++;	/* trailing null */
370138c8a9a5SSteve French 		name_len *= 2;
370238c8a9a5SSteve French 	} else {
370338c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, search_name);
370438c8a9a5SSteve French 	}
370538c8a9a5SSteve French 
370638c8a9a5SSteve French 	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
370738c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
370838c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
370938c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
371038c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(4000);
371138c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
371238c8a9a5SSteve French 	pSMB->Reserved = 0;
371338c8a9a5SSteve French 	pSMB->Flags = 0;
371438c8a9a5SSteve French 	pSMB->Timeout = 0;
371538c8a9a5SSteve French 	pSMB->Reserved2 = 0;
371638c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
371738c8a9a5SSteve French 	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
371838c8a9a5SSteve French 	pSMB->DataCount = 0;
371938c8a9a5SSteve French 	pSMB->DataOffset = 0;
372038c8a9a5SSteve French 	pSMB->SetupCount = 1;
372138c8a9a5SSteve French 	pSMB->Reserved3 = 0;
372238c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
372338c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
372438c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
372538c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
372638c8a9a5SSteve French 	if (legacy)
372738c8a9a5SSteve French 		pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
372838c8a9a5SSteve French 	else
372938c8a9a5SSteve French 		pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
373038c8a9a5SSteve French 	pSMB->Reserved4 = 0;
373138c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
373238c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
373338c8a9a5SSteve French 
373438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
373538c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
373638c8a9a5SSteve French 	if (rc) {
373738c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
373838c8a9a5SSteve French 	} else {		/* decode response */
373938c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
374038c8a9a5SSteve French 
374138c8a9a5SSteve French 		if (rc) /* BB add auto retry on EOPNOTSUPP? */
374238c8a9a5SSteve French 			rc = -EIO;
374338c8a9a5SSteve French 		else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
374438c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
374538c8a9a5SSteve French 		else if (legacy && get_bcc(&pSMBr->hdr) < 24)
374638c8a9a5SSteve French 			rc = -EIO;  /* 24 or 26 expected but we do not read
374738c8a9a5SSteve French 					last field */
374838c8a9a5SSteve French 		else if (data) {
374938c8a9a5SSteve French 			int size;
375038c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
375138c8a9a5SSteve French 
375238c8a9a5SSteve French 			/*
375338c8a9a5SSteve French 			 * On legacy responses we do not read the last field,
375438c8a9a5SSteve French 			 * EAsize, fortunately since it varies by subdialect and
375538c8a9a5SSteve French 			 * also note it differs on Set vs Get, ie two bytes or 4
375638c8a9a5SSteve French 			 * bytes depending but we don't care here.
375738c8a9a5SSteve French 			 */
375838c8a9a5SSteve French 			if (legacy)
375938c8a9a5SSteve French 				size = sizeof(FILE_INFO_STANDARD);
376038c8a9a5SSteve French 			else
376138c8a9a5SSteve French 				size = sizeof(FILE_ALL_INFO);
376238c8a9a5SSteve French 			memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
376338c8a9a5SSteve French 			       data_offset, size);
376438c8a9a5SSteve French 		} else
376538c8a9a5SSteve French 		    rc = -ENOMEM;
376638c8a9a5SSteve French 	}
376738c8a9a5SSteve French 	cifs_buf_release(pSMB);
376838c8a9a5SSteve French 	if (rc == -EAGAIN)
376938c8a9a5SSteve French 		goto QPathInfoRetry;
377038c8a9a5SSteve French 
377138c8a9a5SSteve French 	return rc;
377238c8a9a5SSteve French }
377338c8a9a5SSteve French 
377438c8a9a5SSteve French int
CIFSSMBUnixQFileInfo(const unsigned int xid,struct cifs_tcon * tcon,u16 netfid,FILE_UNIX_BASIC_INFO * pFindData)377538c8a9a5SSteve French CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
377638c8a9a5SSteve French 		 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
377738c8a9a5SSteve French {
377838c8a9a5SSteve French 	struct smb_t2_qfi_req *pSMB = NULL;
377938c8a9a5SSteve French 	struct smb_t2_qfi_rsp *pSMBr = NULL;
378038c8a9a5SSteve French 	int rc = 0;
378138c8a9a5SSteve French 	int bytes_returned;
378238c8a9a5SSteve French 	__u16 params, byte_count;
378338c8a9a5SSteve French 
378438c8a9a5SSteve French UnixQFileInfoRetry:
378538c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
378638c8a9a5SSteve French 		      (void **) &pSMBr);
378738c8a9a5SSteve French 	if (rc)
378838c8a9a5SSteve French 		return rc;
378938c8a9a5SSteve French 
379038c8a9a5SSteve French 	params = 2 /* level */ + 2 /* fid */;
379138c8a9a5SSteve French 	pSMB->t2.TotalDataCount = 0;
379238c8a9a5SSteve French 	pSMB->t2.MaxParameterCount = cpu_to_le16(4);
379338c8a9a5SSteve French 	/* BB find exact max data count below from sess structure BB */
379438c8a9a5SSteve French 	pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
379538c8a9a5SSteve French 	pSMB->t2.MaxSetupCount = 0;
379638c8a9a5SSteve French 	pSMB->t2.Reserved = 0;
379738c8a9a5SSteve French 	pSMB->t2.Flags = 0;
379838c8a9a5SSteve French 	pSMB->t2.Timeout = 0;
379938c8a9a5SSteve French 	pSMB->t2.Reserved2 = 0;
380038c8a9a5SSteve French 	pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
380138c8a9a5SSteve French 					       Fid) - 4);
380238c8a9a5SSteve French 	pSMB->t2.DataCount = 0;
380338c8a9a5SSteve French 	pSMB->t2.DataOffset = 0;
380438c8a9a5SSteve French 	pSMB->t2.SetupCount = 1;
380538c8a9a5SSteve French 	pSMB->t2.Reserved3 = 0;
380638c8a9a5SSteve French 	pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
380738c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
380838c8a9a5SSteve French 	pSMB->t2.TotalParameterCount = cpu_to_le16(params);
380938c8a9a5SSteve French 	pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
381038c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
381138c8a9a5SSteve French 	pSMB->Pad = 0;
381238c8a9a5SSteve French 	pSMB->Fid = netfid;
381338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
381438c8a9a5SSteve French 	pSMB->t2.ByteCount = cpu_to_le16(byte_count);
381538c8a9a5SSteve French 
381638c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
381738c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
381838c8a9a5SSteve French 	if (rc) {
381938c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in UnixQFileInfo = %d\n", rc);
382038c8a9a5SSteve French 	} else {		/* decode response */
382138c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
382238c8a9a5SSteve French 
382338c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
382438c8a9a5SSteve French 			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
382538c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
382638c8a9a5SSteve French 		} else {
382738c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
382838c8a9a5SSteve French 			memcpy((char *) pFindData,
382938c8a9a5SSteve French 			       (char *) &pSMBr->hdr.Protocol +
383038c8a9a5SSteve French 			       data_offset,
383138c8a9a5SSteve French 			       sizeof(FILE_UNIX_BASIC_INFO));
383238c8a9a5SSteve French 		}
383338c8a9a5SSteve French 	}
383438c8a9a5SSteve French 
383538c8a9a5SSteve French 	cifs_buf_release(pSMB);
383638c8a9a5SSteve French 	if (rc == -EAGAIN)
383738c8a9a5SSteve French 		goto UnixQFileInfoRetry;
383838c8a9a5SSteve French 
383938c8a9a5SSteve French 	return rc;
384038c8a9a5SSteve French }
384138c8a9a5SSteve French 
384238c8a9a5SSteve French int
CIFSSMBUnixQPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,FILE_UNIX_BASIC_INFO * pFindData,const struct nls_table * nls_codepage,int remap)384338c8a9a5SSteve French CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
384438c8a9a5SSteve French 		     const unsigned char *searchName,
384538c8a9a5SSteve French 		     FILE_UNIX_BASIC_INFO *pFindData,
384638c8a9a5SSteve French 		     const struct nls_table *nls_codepage, int remap)
384738c8a9a5SSteve French {
384838c8a9a5SSteve French /* SMB_QUERY_FILE_UNIX_BASIC */
384938c8a9a5SSteve French 	TRANSACTION2_QPI_REQ *pSMB = NULL;
385038c8a9a5SSteve French 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
385138c8a9a5SSteve French 	int rc = 0;
385238c8a9a5SSteve French 	int bytes_returned = 0;
385338c8a9a5SSteve French 	int name_len;
385438c8a9a5SSteve French 	__u16 params, byte_count;
385538c8a9a5SSteve French 
385638c8a9a5SSteve French 	cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
385738c8a9a5SSteve French UnixQPathInfoRetry:
385838c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
385938c8a9a5SSteve French 		      (void **) &pSMBr);
386038c8a9a5SSteve French 	if (rc)
386138c8a9a5SSteve French 		return rc;
386238c8a9a5SSteve French 
386338c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
386438c8a9a5SSteve French 		name_len =
386538c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
386638c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
386738c8a9a5SSteve French 		name_len++;	/* trailing null */
386838c8a9a5SSteve French 		name_len *= 2;
386938c8a9a5SSteve French 	} else {
387038c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, searchName);
387138c8a9a5SSteve French 	}
387238c8a9a5SSteve French 
387338c8a9a5SSteve French 	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
387438c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
387538c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
387638c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
387738c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(4000);
387838c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
387938c8a9a5SSteve French 	pSMB->Reserved = 0;
388038c8a9a5SSteve French 	pSMB->Flags = 0;
388138c8a9a5SSteve French 	pSMB->Timeout = 0;
388238c8a9a5SSteve French 	pSMB->Reserved2 = 0;
388338c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
388438c8a9a5SSteve French 	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
388538c8a9a5SSteve French 	pSMB->DataCount = 0;
388638c8a9a5SSteve French 	pSMB->DataOffset = 0;
388738c8a9a5SSteve French 	pSMB->SetupCount = 1;
388838c8a9a5SSteve French 	pSMB->Reserved3 = 0;
388938c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
389038c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
389138c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
389238c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
389338c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
389438c8a9a5SSteve French 	pSMB->Reserved4 = 0;
389538c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
389638c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
389738c8a9a5SSteve French 
389838c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
389938c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
390038c8a9a5SSteve French 	if (rc) {
390138c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in UnixQPathInfo = %d\n", rc);
390238c8a9a5SSteve French 	} else {		/* decode response */
390338c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
390438c8a9a5SSteve French 
390538c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
390638c8a9a5SSteve French 			cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
390738c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
390838c8a9a5SSteve French 		} else {
390938c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
391038c8a9a5SSteve French 			memcpy((char *) pFindData,
391138c8a9a5SSteve French 			       (char *) &pSMBr->hdr.Protocol +
391238c8a9a5SSteve French 			       data_offset,
391338c8a9a5SSteve French 			       sizeof(FILE_UNIX_BASIC_INFO));
391438c8a9a5SSteve French 		}
391538c8a9a5SSteve French 	}
391638c8a9a5SSteve French 	cifs_buf_release(pSMB);
391738c8a9a5SSteve French 	if (rc == -EAGAIN)
391838c8a9a5SSteve French 		goto UnixQPathInfoRetry;
391938c8a9a5SSteve French 
392038c8a9a5SSteve French 	return rc;
392138c8a9a5SSteve French }
392238c8a9a5SSteve French 
392338c8a9a5SSteve French /* xid, tcon, searchName and codepage are input parms, rest are returned */
392438c8a9a5SSteve French int
CIFSFindFirst(const unsigned int xid,struct cifs_tcon * tcon,const char * searchName,struct cifs_sb_info * cifs_sb,__u16 * pnetfid,__u16 search_flags,struct cifs_search_info * psrch_inf,bool msearch)392538c8a9a5SSteve French CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
392638c8a9a5SSteve French 	      const char *searchName, struct cifs_sb_info *cifs_sb,
392738c8a9a5SSteve French 	      __u16 *pnetfid, __u16 search_flags,
392838c8a9a5SSteve French 	      struct cifs_search_info *psrch_inf, bool msearch)
392938c8a9a5SSteve French {
393038c8a9a5SSteve French /* level 257 SMB_ */
393138c8a9a5SSteve French 	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
393238c8a9a5SSteve French 	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
393338c8a9a5SSteve French 	T2_FFIRST_RSP_PARMS *parms;
3934032137feSPaulo Alcantara 	struct nls_table *nls_codepage;
3935032137feSPaulo Alcantara 	unsigned int lnoff;
3936032137feSPaulo Alcantara 	__u16 params, byte_count;
393738c8a9a5SSteve French 	int bytes_returned = 0;
393838c8a9a5SSteve French 	int name_len, remap;
3939032137feSPaulo Alcantara 	int rc = 0;
394038c8a9a5SSteve French 
394138c8a9a5SSteve French 	cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
394238c8a9a5SSteve French 
394338c8a9a5SSteve French findFirstRetry:
394438c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
394538c8a9a5SSteve French 		      (void **) &pSMBr);
394638c8a9a5SSteve French 	if (rc)
394738c8a9a5SSteve French 		return rc;
394838c8a9a5SSteve French 
394938c8a9a5SSteve French 	nls_codepage = cifs_sb->local_nls;
395038c8a9a5SSteve French 	remap = cifs_remap(cifs_sb);
395138c8a9a5SSteve French 
395238c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
395338c8a9a5SSteve French 		name_len =
395438c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
395538c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
395638c8a9a5SSteve French 		/* We can not add the asterik earlier in case
395738c8a9a5SSteve French 		it got remapped to 0xF03A as if it were part of the
395838c8a9a5SSteve French 		directory name instead of a wildcard */
395938c8a9a5SSteve French 		name_len *= 2;
396038c8a9a5SSteve French 		if (msearch) {
396138c8a9a5SSteve French 			pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
396238c8a9a5SSteve French 			pSMB->FileName[name_len+1] = 0;
396338c8a9a5SSteve French 			pSMB->FileName[name_len+2] = '*';
396438c8a9a5SSteve French 			pSMB->FileName[name_len+3] = 0;
396538c8a9a5SSteve French 			name_len += 4; /* now the trailing null */
396638c8a9a5SSteve French 			/* null terminate just in case */
396738c8a9a5SSteve French 			pSMB->FileName[name_len] = 0;
396838c8a9a5SSteve French 			pSMB->FileName[name_len+1] = 0;
396938c8a9a5SSteve French 			name_len += 2;
397038c8a9a5SSteve French 		}
397138c8a9a5SSteve French 	} else {
397238c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, searchName);
397338c8a9a5SSteve French 		if (msearch) {
397438c8a9a5SSteve French 			if (WARN_ON_ONCE(name_len > PATH_MAX-2))
397538c8a9a5SSteve French 				name_len = PATH_MAX-2;
397638c8a9a5SSteve French 			/* overwrite nul byte */
397738c8a9a5SSteve French 			pSMB->FileName[name_len-1] = CIFS_DIR_SEP(cifs_sb);
397838c8a9a5SSteve French 			pSMB->FileName[name_len] = '*';
397938c8a9a5SSteve French 			pSMB->FileName[name_len+1] = 0;
398038c8a9a5SSteve French 			name_len += 2;
398138c8a9a5SSteve French 		}
398238c8a9a5SSteve French 	}
398338c8a9a5SSteve French 
398438c8a9a5SSteve French 	params = 12 + name_len /* includes null */ ;
398538c8a9a5SSteve French 	pSMB->TotalDataCount = 0;	/* no EAs */
398638c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(10);
398738c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
398838c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
398938c8a9a5SSteve French 	pSMB->Reserved = 0;
399038c8a9a5SSteve French 	pSMB->Flags = 0;
399138c8a9a5SSteve French 	pSMB->Timeout = 0;
399238c8a9a5SSteve French 	pSMB->Reserved2 = 0;
399338c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
399438c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
399538c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
399638c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(
399738c8a9a5SSteve French 	      offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
399838c8a9a5SSteve French 		- 4);
399938c8a9a5SSteve French 	pSMB->DataCount = 0;
400038c8a9a5SSteve French 	pSMB->DataOffset = 0;
400138c8a9a5SSteve French 	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
400238c8a9a5SSteve French 	pSMB->Reserved3 = 0;
400338c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
400438c8a9a5SSteve French 	pSMB->SearchAttributes =
400538c8a9a5SSteve French 	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
400638c8a9a5SSteve French 			ATTR_DIRECTORY);
400738c8a9a5SSteve French 	pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
400838c8a9a5SSteve French 	pSMB->SearchFlags = cpu_to_le16(search_flags);
400938c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
401038c8a9a5SSteve French 
401138c8a9a5SSteve French 	/* BB what should we set StorageType to? Does it matter? BB */
401238c8a9a5SSteve French 	pSMB->SearchStorageType = 0;
401338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
401438c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
401538c8a9a5SSteve French 
401638c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
401738c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
401838c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
401938c8a9a5SSteve French 
4020032137feSPaulo Alcantara 	if (rc) {
4021032137feSPaulo Alcantara 		/*
4022032137feSPaulo Alcantara 		 * BB: add logic to retry regular search if Unix search rejected
4023032137feSPaulo Alcantara 		 * unexpectedly by server.
4024032137feSPaulo Alcantara 		 */
4025032137feSPaulo Alcantara 		/* BB: add code to handle unsupported level rc */
402638c8a9a5SSteve French 		cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
402738c8a9a5SSteve French 		cifs_buf_release(pSMB);
4028032137feSPaulo Alcantara 		/*
4029032137feSPaulo Alcantara 		 * BB: eventually could optimize out free and realloc of buf for
4030032137feSPaulo Alcantara 		 * this case.
4031032137feSPaulo Alcantara 		 */
403238c8a9a5SSteve French 		if (rc == -EAGAIN)
403338c8a9a5SSteve French 			goto findFirstRetry;
4034032137feSPaulo Alcantara 		return rc;
4035032137feSPaulo Alcantara 	}
4036032137feSPaulo Alcantara 	/* decode response */
403738c8a9a5SSteve French 	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4038032137feSPaulo Alcantara 	if (rc) {
4039032137feSPaulo Alcantara 		cifs_buf_release(pSMB);
4040032137feSPaulo Alcantara 		return rc;
4041032137feSPaulo Alcantara 	}
404238c8a9a5SSteve French 
4043032137feSPaulo Alcantara 	psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
404438c8a9a5SSteve French 	psrch_inf->ntwrk_buf_start = (char *)pSMBr;
404538c8a9a5SSteve French 	psrch_inf->smallBuf = false;
4046032137feSPaulo Alcantara 	psrch_inf->srch_entries_start = (char *)&pSMBr->hdr.Protocol +
404738c8a9a5SSteve French 		le16_to_cpu(pSMBr->t2.DataOffset);
4048032137feSPaulo Alcantara 
404938c8a9a5SSteve French 	parms = (T2_FFIRST_RSP_PARMS *)((char *)&pSMBr->hdr.Protocol +
405038c8a9a5SSteve French 					le16_to_cpu(pSMBr->t2.ParameterOffset));
4051032137feSPaulo Alcantara 	psrch_inf->endOfSearch = !!parms->EndofSearch;
405238c8a9a5SSteve French 
4053032137feSPaulo Alcantara 	psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
405438c8a9a5SSteve French 	psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
405538c8a9a5SSteve French 		psrch_inf->entries_in_buffer;
405638c8a9a5SSteve French 	lnoff = le16_to_cpu(parms->LastNameOffset);
405738c8a9a5SSteve French 	if (CIFSMaxBufSize < lnoff) {
405838c8a9a5SSteve French 		cifs_dbg(VFS, "ignoring corrupt resume name\n");
405938c8a9a5SSteve French 		psrch_inf->last_entry = NULL;
4060032137feSPaulo Alcantara 	} else {
4061032137feSPaulo Alcantara 		psrch_inf->last_entry = psrch_inf->srch_entries_start + lnoff;
406238c8a9a5SSteve French 		if (pnetfid)
406338c8a9a5SSteve French 			*pnetfid = parms->SearchHandle;
406438c8a9a5SSteve French 	}
4065032137feSPaulo Alcantara 	return 0;
406638c8a9a5SSteve French }
406738c8a9a5SSteve French 
CIFSFindNext(const unsigned int xid,struct cifs_tcon * tcon,__u16 searchHandle,__u16 search_flags,struct cifs_search_info * psrch_inf)406838c8a9a5SSteve French int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
406938c8a9a5SSteve French 		 __u16 searchHandle, __u16 search_flags,
407038c8a9a5SSteve French 		 struct cifs_search_info *psrch_inf)
407138c8a9a5SSteve French {
407238c8a9a5SSteve French 	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
407338c8a9a5SSteve French 	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
407438c8a9a5SSteve French 	T2_FNEXT_RSP_PARMS *parms;
407538c8a9a5SSteve French 	unsigned int name_len;
4076215533f8SPaulo Alcantara 	unsigned int lnoff;
407738c8a9a5SSteve French 	__u16 params, byte_count;
4078215533f8SPaulo Alcantara 	char *response_data;
4079215533f8SPaulo Alcantara 	int bytes_returned;
4080215533f8SPaulo Alcantara 	int rc = 0;
408138c8a9a5SSteve French 
408238c8a9a5SSteve French 	cifs_dbg(FYI, "In FindNext\n");
408338c8a9a5SSteve French 
408438c8a9a5SSteve French 	if (psrch_inf->endOfSearch)
408538c8a9a5SSteve French 		return -ENOENT;
408638c8a9a5SSteve French 
408738c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
408838c8a9a5SSteve French 		(void **) &pSMBr);
408938c8a9a5SSteve French 	if (rc)
409038c8a9a5SSteve French 		return rc;
409138c8a9a5SSteve French 
409238c8a9a5SSteve French 	params = 14; /* includes 2 bytes of null string, converted to LE below*/
409338c8a9a5SSteve French 	byte_count = 0;
409438c8a9a5SSteve French 	pSMB->TotalDataCount = 0;       /* no EAs */
409538c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(8);
409638c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
409738c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
409838c8a9a5SSteve French 	pSMB->Reserved = 0;
409938c8a9a5SSteve French 	pSMB->Flags = 0;
410038c8a9a5SSteve French 	pSMB->Timeout = 0;
410138c8a9a5SSteve French 	pSMB->Reserved2 = 0;
410238c8a9a5SSteve French 	pSMB->ParameterOffset =  cpu_to_le16(
410338c8a9a5SSteve French 	      offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
410438c8a9a5SSteve French 	pSMB->DataCount = 0;
410538c8a9a5SSteve French 	pSMB->DataOffset = 0;
410638c8a9a5SSteve French 	pSMB->SetupCount = 1;
410738c8a9a5SSteve French 	pSMB->Reserved3 = 0;
410838c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
410938c8a9a5SSteve French 	pSMB->SearchHandle = searchHandle;      /* always kept as le */
411038c8a9a5SSteve French 	pSMB->SearchCount =
411138c8a9a5SSteve French 		cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
411238c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
411338c8a9a5SSteve French 	pSMB->ResumeKey = psrch_inf->resume_key;
411438c8a9a5SSteve French 	pSMB->SearchFlags = cpu_to_le16(search_flags);
411538c8a9a5SSteve French 
411638c8a9a5SSteve French 	name_len = psrch_inf->resume_name_len;
411738c8a9a5SSteve French 	params += name_len;
411838c8a9a5SSteve French 	if (name_len < PATH_MAX) {
411938c8a9a5SSteve French 		memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
412038c8a9a5SSteve French 		byte_count += name_len;
412138c8a9a5SSteve French 		/* 14 byte parm len above enough for 2 byte null terminator */
412238c8a9a5SSteve French 		pSMB->ResumeFileName[name_len] = 0;
412338c8a9a5SSteve French 		pSMB->ResumeFileName[name_len+1] = 0;
412438c8a9a5SSteve French 	} else {
4125215533f8SPaulo Alcantara 		cifs_buf_release(pSMB);
4126215533f8SPaulo Alcantara 		return -EINVAL;
412738c8a9a5SSteve French 	}
412838c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
412938c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
413038c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
413138c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
413238c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
413338c8a9a5SSteve French 
413438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
413538c8a9a5SSteve French 			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
413638c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
4137215533f8SPaulo Alcantara 
413838c8a9a5SSteve French 	if (rc) {
4139215533f8SPaulo Alcantara 		cifs_buf_release(pSMB);
414038c8a9a5SSteve French 		if (rc == -EBADF) {
414138c8a9a5SSteve French 			psrch_inf->endOfSearch = true;
414238c8a9a5SSteve French 			rc = 0; /* search probably was closed at end of search*/
4143215533f8SPaulo Alcantara 		} else {
414438c8a9a5SSteve French 			cifs_dbg(FYI, "FindNext returned = %d\n", rc);
4145215533f8SPaulo Alcantara 		}
4146215533f8SPaulo Alcantara 		return rc;
4147215533f8SPaulo Alcantara 	}
4148215533f8SPaulo Alcantara 
4149215533f8SPaulo Alcantara 	/* decode response */
415038c8a9a5SSteve French 	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4151215533f8SPaulo Alcantara 	if (rc) {
4152215533f8SPaulo Alcantara 		cifs_buf_release(pSMB);
4153215533f8SPaulo Alcantara 		return rc;
4154215533f8SPaulo Alcantara 	}
415538c8a9a5SSteve French 	/* BB fixme add lock for file (srch_info) struct here */
4156215533f8SPaulo Alcantara 	psrch_inf->unicode = !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE);
415738c8a9a5SSteve French 	response_data = (char *)&pSMBr->hdr.Protocol +
415838c8a9a5SSteve French 		le16_to_cpu(pSMBr->t2.ParameterOffset);
415938c8a9a5SSteve French 	parms = (T2_FNEXT_RSP_PARMS *)response_data;
416038c8a9a5SSteve French 	response_data = (char *)&pSMBr->hdr.Protocol +
416138c8a9a5SSteve French 		le16_to_cpu(pSMBr->t2.DataOffset);
4162215533f8SPaulo Alcantara 
416338c8a9a5SSteve French 	if (psrch_inf->smallBuf)
4164215533f8SPaulo Alcantara 		cifs_small_buf_release(psrch_inf->ntwrk_buf_start);
416538c8a9a5SSteve French 	else
416638c8a9a5SSteve French 		cifs_buf_release(psrch_inf->ntwrk_buf_start);
4167215533f8SPaulo Alcantara 
416838c8a9a5SSteve French 	psrch_inf->srch_entries_start = response_data;
416938c8a9a5SSteve French 	psrch_inf->ntwrk_buf_start = (char *)pSMB;
417038c8a9a5SSteve French 	psrch_inf->smallBuf = false;
4171215533f8SPaulo Alcantara 	psrch_inf->endOfSearch = !!parms->EndofSearch;
4172215533f8SPaulo Alcantara 	psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
4173215533f8SPaulo Alcantara 	psrch_inf->index_of_last_entry += psrch_inf->entries_in_buffer;
417438c8a9a5SSteve French 	lnoff = le16_to_cpu(parms->LastNameOffset);
417538c8a9a5SSteve French 	if (CIFSMaxBufSize < lnoff) {
417638c8a9a5SSteve French 		cifs_dbg(VFS, "ignoring corrupt resume name\n");
417738c8a9a5SSteve French 		psrch_inf->last_entry = NULL;
4178215533f8SPaulo Alcantara 	} else {
417938c8a9a5SSteve French 		psrch_inf->last_entry =
418038c8a9a5SSteve French 			psrch_inf->srch_entries_start + lnoff;
4181215533f8SPaulo Alcantara 	}
418238c8a9a5SSteve French 	/* BB fixme add unlock here */
418338c8a9a5SSteve French 
4184215533f8SPaulo Alcantara 	/*
4185215533f8SPaulo Alcantara 	 * BB: On error, should we leave previous search buf
4186215533f8SPaulo Alcantara 	 * (and count and last entry fields) intact or free the previous one?
4187215533f8SPaulo Alcantara 	 *
4188215533f8SPaulo Alcantara 	 * Note: On -EAGAIN error only caller can retry on handle based calls
4189215533f8SPaulo Alcantara 	 * since file handle passed in no longer valid.
4190215533f8SPaulo Alcantara 	 */
4191215533f8SPaulo Alcantara 	return 0;
419238c8a9a5SSteve French }
419338c8a9a5SSteve French 
419438c8a9a5SSteve French int
CIFSFindClose(const unsigned int xid,struct cifs_tcon * tcon,const __u16 searchHandle)419538c8a9a5SSteve French CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
419638c8a9a5SSteve French 	      const __u16 searchHandle)
419738c8a9a5SSteve French {
419838c8a9a5SSteve French 	int rc = 0;
419938c8a9a5SSteve French 	FINDCLOSE_REQ *pSMB = NULL;
420038c8a9a5SSteve French 
420138c8a9a5SSteve French 	cifs_dbg(FYI, "In CIFSSMBFindClose\n");
420238c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
420338c8a9a5SSteve French 
420438c8a9a5SSteve French 	/* no sense returning error if session restarted
420538c8a9a5SSteve French 		as file handle has been closed */
420638c8a9a5SSteve French 	if (rc == -EAGAIN)
420738c8a9a5SSteve French 		return 0;
420838c8a9a5SSteve French 	if (rc)
420938c8a9a5SSteve French 		return rc;
421038c8a9a5SSteve French 
421138c8a9a5SSteve French 	pSMB->FileID = searchHandle;
421238c8a9a5SSteve French 	pSMB->ByteCount = 0;
421338c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
421438c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
421538c8a9a5SSteve French 	if (rc)
421638c8a9a5SSteve French 		cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
421738c8a9a5SSteve French 
421838c8a9a5SSteve French 	cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
421938c8a9a5SSteve French 
422038c8a9a5SSteve French 	/* Since session is dead, search handle closed on server already */
422138c8a9a5SSteve French 	if (rc == -EAGAIN)
422238c8a9a5SSteve French 		rc = 0;
422338c8a9a5SSteve French 
422438c8a9a5SSteve French 	return rc;
422538c8a9a5SSteve French }
422638c8a9a5SSteve French 
422738c8a9a5SSteve French int
CIFSGetSrvInodeNumber(const unsigned int xid,struct cifs_tcon * tcon,const char * search_name,__u64 * inode_number,const struct nls_table * nls_codepage,int remap)422838c8a9a5SSteve French CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
422938c8a9a5SSteve French 		      const char *search_name, __u64 *inode_number,
423038c8a9a5SSteve French 		      const struct nls_table *nls_codepage, int remap)
423138c8a9a5SSteve French {
423238c8a9a5SSteve French 	int rc = 0;
423338c8a9a5SSteve French 	TRANSACTION2_QPI_REQ *pSMB = NULL;
423438c8a9a5SSteve French 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
423538c8a9a5SSteve French 	int name_len, bytes_returned;
423638c8a9a5SSteve French 	__u16 params, byte_count;
423738c8a9a5SSteve French 
423838c8a9a5SSteve French 	cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
423938c8a9a5SSteve French 	if (tcon == NULL)
424038c8a9a5SSteve French 		return -ENODEV;
424138c8a9a5SSteve French 
424238c8a9a5SSteve French GetInodeNumberRetry:
424338c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
424438c8a9a5SSteve French 		      (void **) &pSMBr);
424538c8a9a5SSteve French 	if (rc)
424638c8a9a5SSteve French 		return rc;
424738c8a9a5SSteve French 
424838c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
424938c8a9a5SSteve French 		name_len =
425038c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *) pSMB->FileName,
425138c8a9a5SSteve French 					   search_name, PATH_MAX, nls_codepage,
425238c8a9a5SSteve French 					   remap);
425338c8a9a5SSteve French 		name_len++;     /* trailing null */
425438c8a9a5SSteve French 		name_len *= 2;
425538c8a9a5SSteve French 	} else {
425638c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, search_name);
425738c8a9a5SSteve French 	}
425838c8a9a5SSteve French 
425938c8a9a5SSteve French 	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
426038c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
426138c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
426238c8a9a5SSteve French 	/* BB find exact max data count below from sess structure BB */
426338c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(4000);
426438c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
426538c8a9a5SSteve French 	pSMB->Reserved = 0;
426638c8a9a5SSteve French 	pSMB->Flags = 0;
426738c8a9a5SSteve French 	pSMB->Timeout = 0;
426838c8a9a5SSteve French 	pSMB->Reserved2 = 0;
426938c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
427038c8a9a5SSteve French 		struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
427138c8a9a5SSteve French 	pSMB->DataCount = 0;
427238c8a9a5SSteve French 	pSMB->DataOffset = 0;
427338c8a9a5SSteve French 	pSMB->SetupCount = 1;
427438c8a9a5SSteve French 	pSMB->Reserved3 = 0;
427538c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
427638c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
427738c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
427838c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
427938c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
428038c8a9a5SSteve French 	pSMB->Reserved4 = 0;
428138c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
428238c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
428338c8a9a5SSteve French 
428438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
428538c8a9a5SSteve French 		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
428638c8a9a5SSteve French 	if (rc) {
428738c8a9a5SSteve French 		cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
428838c8a9a5SSteve French 	} else {
428938c8a9a5SSteve French 		/* decode response */
429038c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
429138c8a9a5SSteve French 		/* BB also check enough total bytes returned */
429238c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 2)
429338c8a9a5SSteve French 			/* If rc should we check for EOPNOSUPP and
429438c8a9a5SSteve French 			disable the srvino flag? or in caller? */
429538c8a9a5SSteve French 			rc = -EIO;      /* bad smb */
429638c8a9a5SSteve French 		else {
429738c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
429838c8a9a5SSteve French 			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
429938c8a9a5SSteve French 			struct file_internal_info *pfinfo;
430038c8a9a5SSteve French 			/* BB Do we need a cast or hash here ? */
430138c8a9a5SSteve French 			if (count < 8) {
430238c8a9a5SSteve French 				cifs_dbg(FYI, "Invalid size ret in QryIntrnlInf\n");
430338c8a9a5SSteve French 				rc = -EIO;
430438c8a9a5SSteve French 				goto GetInodeNumOut;
430538c8a9a5SSteve French 			}
430638c8a9a5SSteve French 			pfinfo = (struct file_internal_info *)
430738c8a9a5SSteve French 				(data_offset + (char *) &pSMBr->hdr.Protocol);
430838c8a9a5SSteve French 			*inode_number = le64_to_cpu(pfinfo->UniqueId);
430938c8a9a5SSteve French 		}
431038c8a9a5SSteve French 	}
431138c8a9a5SSteve French GetInodeNumOut:
431238c8a9a5SSteve French 	cifs_buf_release(pSMB);
431338c8a9a5SSteve French 	if (rc == -EAGAIN)
431438c8a9a5SSteve French 		goto GetInodeNumberRetry;
431538c8a9a5SSteve French 	return rc;
431638c8a9a5SSteve French }
431738c8a9a5SSteve French 
431838c8a9a5SSteve French int
CIFSGetDFSRefer(const unsigned int xid,struct cifs_ses * ses,const char * search_name,struct dfs_info3_param ** target_nodes,unsigned int * num_of_nodes,const struct nls_table * nls_codepage,int remap)431938c8a9a5SSteve French CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
432038c8a9a5SSteve French 		const char *search_name, struct dfs_info3_param **target_nodes,
432138c8a9a5SSteve French 		unsigned int *num_of_nodes,
432238c8a9a5SSteve French 		const struct nls_table *nls_codepage, int remap)
432338c8a9a5SSteve French {
432438c8a9a5SSteve French /* TRANS2_GET_DFS_REFERRAL */
432538c8a9a5SSteve French 	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
432638c8a9a5SSteve French 	TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
432738c8a9a5SSteve French 	int rc = 0;
432838c8a9a5SSteve French 	int bytes_returned;
432938c8a9a5SSteve French 	int name_len;
433038c8a9a5SSteve French 	__u16 params, byte_count;
433138c8a9a5SSteve French 	*num_of_nodes = 0;
433238c8a9a5SSteve French 	*target_nodes = NULL;
433338c8a9a5SSteve French 
433438c8a9a5SSteve French 	cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
433538c8a9a5SSteve French 	if (ses == NULL || ses->tcon_ipc == NULL)
433638c8a9a5SSteve French 		return -ENODEV;
433738c8a9a5SSteve French 
433838c8a9a5SSteve French getDFSRetry:
433938c8a9a5SSteve French 	/*
434038c8a9a5SSteve French 	 * Use smb_init_no_reconnect() instead of smb_init() as
434138c8a9a5SSteve French 	 * CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus
434238c8a9a5SSteve French 	 * causing an infinite recursion.
434338c8a9a5SSteve French 	 */
434438c8a9a5SSteve French 	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
434538c8a9a5SSteve French 				   (void **)&pSMB, (void **)&pSMBr);
434638c8a9a5SSteve French 	if (rc)
434738c8a9a5SSteve French 		return rc;
434838c8a9a5SSteve French 
434938c8a9a5SSteve French 	/* server pointer checked in called function,
435038c8a9a5SSteve French 	but should never be null here anyway */
435138c8a9a5SSteve French 	pSMB->hdr.Mid = get_next_mid(ses->server);
435238c8a9a5SSteve French 	pSMB->hdr.Tid = ses->tcon_ipc->tid;
435338c8a9a5SSteve French 	pSMB->hdr.Uid = ses->Suid;
435438c8a9a5SSteve French 	if (ses->capabilities & CAP_STATUS32)
435538c8a9a5SSteve French 		pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
435638c8a9a5SSteve French 	if (ses->capabilities & CAP_DFS)
435738c8a9a5SSteve French 		pSMB->hdr.Flags2 |= SMBFLG2_DFS;
435838c8a9a5SSteve French 
435938c8a9a5SSteve French 	if (ses->capabilities & CAP_UNICODE) {
436038c8a9a5SSteve French 		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
436138c8a9a5SSteve French 		name_len =
436238c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
436338c8a9a5SSteve French 				       search_name, PATH_MAX, nls_codepage,
436438c8a9a5SSteve French 				       remap);
436538c8a9a5SSteve French 		name_len++;	/* trailing null */
436638c8a9a5SSteve French 		name_len *= 2;
436738c8a9a5SSteve French 	} else {	/* BB improve the check for buffer overruns BB */
436838c8a9a5SSteve French 		name_len = copy_path_name(pSMB->RequestFileName, search_name);
436938c8a9a5SSteve French 	}
437038c8a9a5SSteve French 
437138c8a9a5SSteve French 	if (ses->server->sign)
437238c8a9a5SSteve French 		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
437338c8a9a5SSteve French 
437438c8a9a5SSteve French 	pSMB->hdr.Uid = ses->Suid;
437538c8a9a5SSteve French 
437638c8a9a5SSteve French 	params = 2 /* level */  + name_len /*includes null */ ;
437738c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
437838c8a9a5SSteve French 	pSMB->DataCount = 0;
437938c8a9a5SSteve French 	pSMB->DataOffset = 0;
438038c8a9a5SSteve French 	pSMB->MaxParameterCount = 0;
438138c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
438238c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(4000);
438338c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
438438c8a9a5SSteve French 	pSMB->Reserved = 0;
438538c8a9a5SSteve French 	pSMB->Flags = 0;
438638c8a9a5SSteve French 	pSMB->Timeout = 0;
438738c8a9a5SSteve French 	pSMB->Reserved2 = 0;
438838c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
438938c8a9a5SSteve French 	  struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
439038c8a9a5SSteve French 	pSMB->SetupCount = 1;
439138c8a9a5SSteve French 	pSMB->Reserved3 = 0;
439238c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
439338c8a9a5SSteve French 	byte_count = params + 3 /* pad */ ;
439438c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
439538c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
439638c8a9a5SSteve French 	pSMB->MaxReferralLevel = cpu_to_le16(3);
439738c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
439838c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
439938c8a9a5SSteve French 
440038c8a9a5SSteve French 	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
440138c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
440238c8a9a5SSteve French 	if (rc) {
440338c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
440438c8a9a5SSteve French 		goto GetDFSRefExit;
440538c8a9a5SSteve French 	}
440638c8a9a5SSteve French 	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
440738c8a9a5SSteve French 
440838c8a9a5SSteve French 	/* BB Also check if enough total bytes returned? */
440938c8a9a5SSteve French 	if (rc || get_bcc(&pSMBr->hdr) < 17) {
441038c8a9a5SSteve French 		rc = -EIO;      /* bad smb */
441138c8a9a5SSteve French 		goto GetDFSRefExit;
441238c8a9a5SSteve French 	}
441338c8a9a5SSteve French 
441438c8a9a5SSteve French 	cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d  Offset %d\n",
441538c8a9a5SSteve French 		 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
441638c8a9a5SSteve French 
441738c8a9a5SSteve French 	/* parse returned result into more usable form */
441838c8a9a5SSteve French 	rc = parse_dfs_referrals(&pSMBr->dfs_data,
441938c8a9a5SSteve French 				 le16_to_cpu(pSMBr->t2.DataCount),
442038c8a9a5SSteve French 				 num_of_nodes, target_nodes, nls_codepage,
442138c8a9a5SSteve French 				 remap, search_name,
442238c8a9a5SSteve French 				 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
442338c8a9a5SSteve French 
442438c8a9a5SSteve French GetDFSRefExit:
442538c8a9a5SSteve French 	cifs_buf_release(pSMB);
442638c8a9a5SSteve French 
442738c8a9a5SSteve French 	if (rc == -EAGAIN)
442838c8a9a5SSteve French 		goto getDFSRetry;
442938c8a9a5SSteve French 
443038c8a9a5SSteve French 	return rc;
443138c8a9a5SSteve French }
443238c8a9a5SSteve French 
443338c8a9a5SSteve French /* Query File System Info such as free space to old servers such as Win 9x */
443438c8a9a5SSteve French int
SMBOldQFSInfo(const unsigned int xid,struct cifs_tcon * tcon,struct kstatfs * FSData)443538c8a9a5SSteve French SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
443638c8a9a5SSteve French 	      struct kstatfs *FSData)
443738c8a9a5SSteve French {
443838c8a9a5SSteve French /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
443938c8a9a5SSteve French 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
444038c8a9a5SSteve French 	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
444138c8a9a5SSteve French 	FILE_SYSTEM_ALLOC_INFO *response_data;
444238c8a9a5SSteve French 	int rc = 0;
444338c8a9a5SSteve French 	int bytes_returned = 0;
444438c8a9a5SSteve French 	__u16 params, byte_count;
444538c8a9a5SSteve French 
444638c8a9a5SSteve French 	cifs_dbg(FYI, "OldQFSInfo\n");
444738c8a9a5SSteve French oldQFSInfoRetry:
444838c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
444938c8a9a5SSteve French 		(void **) &pSMBr);
445038c8a9a5SSteve French 	if (rc)
445138c8a9a5SSteve French 		return rc;
445238c8a9a5SSteve French 
445338c8a9a5SSteve French 	params = 2;     /* level */
445438c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
445538c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
445638c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
445738c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
445838c8a9a5SSteve French 	pSMB->Reserved = 0;
445938c8a9a5SSteve French 	pSMB->Flags = 0;
446038c8a9a5SSteve French 	pSMB->Timeout = 0;
446138c8a9a5SSteve French 	pSMB->Reserved2 = 0;
446238c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
446338c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
446438c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
446538c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
446638c8a9a5SSteve French 	struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
446738c8a9a5SSteve French 	pSMB->DataCount = 0;
446838c8a9a5SSteve French 	pSMB->DataOffset = 0;
446938c8a9a5SSteve French 	pSMB->SetupCount = 1;
447038c8a9a5SSteve French 	pSMB->Reserved3 = 0;
447138c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
447238c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
447338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
447438c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
447538c8a9a5SSteve French 
447638c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
447738c8a9a5SSteve French 		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
447838c8a9a5SSteve French 	if (rc) {
447938c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
448038c8a9a5SSteve French 	} else {                /* decode response */
448138c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
448238c8a9a5SSteve French 
448338c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 18)
448438c8a9a5SSteve French 			rc = -EIO;      /* bad smb */
448538c8a9a5SSteve French 		else {
448638c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
448738c8a9a5SSteve French 			cifs_dbg(FYI, "qfsinf resp BCC: %d  Offset %d\n",
448838c8a9a5SSteve French 				 get_bcc(&pSMBr->hdr), data_offset);
448938c8a9a5SSteve French 
449038c8a9a5SSteve French 			response_data = (FILE_SYSTEM_ALLOC_INFO *)
449138c8a9a5SSteve French 				(((char *) &pSMBr->hdr.Protocol) + data_offset);
449238c8a9a5SSteve French 			FSData->f_bsize =
449338c8a9a5SSteve French 				le16_to_cpu(response_data->BytesPerSector) *
449438c8a9a5SSteve French 				le32_to_cpu(response_data->
449538c8a9a5SSteve French 					SectorsPerAllocationUnit);
449638c8a9a5SSteve French 			/*
449738c8a9a5SSteve French 			 * much prefer larger but if server doesn't report
449838c8a9a5SSteve French 			 * a valid size than 4K is a reasonable minimum
449938c8a9a5SSteve French 			 */
450038c8a9a5SSteve French 			if (FSData->f_bsize < 512)
450138c8a9a5SSteve French 				FSData->f_bsize = 4096;
450238c8a9a5SSteve French 
450338c8a9a5SSteve French 			FSData->f_blocks =
450438c8a9a5SSteve French 			       le32_to_cpu(response_data->TotalAllocationUnits);
450538c8a9a5SSteve French 			FSData->f_bfree = FSData->f_bavail =
450638c8a9a5SSteve French 				le32_to_cpu(response_data->FreeAllocationUnits);
450738c8a9a5SSteve French 			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
450838c8a9a5SSteve French 				 (unsigned long long)FSData->f_blocks,
450938c8a9a5SSteve French 				 (unsigned long long)FSData->f_bfree,
451038c8a9a5SSteve French 				 FSData->f_bsize);
451138c8a9a5SSteve French 		}
451238c8a9a5SSteve French 	}
451338c8a9a5SSteve French 	cifs_buf_release(pSMB);
451438c8a9a5SSteve French 
451538c8a9a5SSteve French 	if (rc == -EAGAIN)
451638c8a9a5SSteve French 		goto oldQFSInfoRetry;
451738c8a9a5SSteve French 
451838c8a9a5SSteve French 	return rc;
451938c8a9a5SSteve French }
452038c8a9a5SSteve French 
452138c8a9a5SSteve French int
CIFSSMBQFSInfo(const unsigned int xid,struct cifs_tcon * tcon,struct kstatfs * FSData)452238c8a9a5SSteve French CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
452338c8a9a5SSteve French 	       struct kstatfs *FSData)
452438c8a9a5SSteve French {
452538c8a9a5SSteve French /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
452638c8a9a5SSteve French 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
452738c8a9a5SSteve French 	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
452838c8a9a5SSteve French 	FILE_SYSTEM_INFO *response_data;
452938c8a9a5SSteve French 	int rc = 0;
453038c8a9a5SSteve French 	int bytes_returned = 0;
453138c8a9a5SSteve French 	__u16 params, byte_count;
453238c8a9a5SSteve French 
453338c8a9a5SSteve French 	cifs_dbg(FYI, "In QFSInfo\n");
453438c8a9a5SSteve French QFSInfoRetry:
453538c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
453638c8a9a5SSteve French 		      (void **) &pSMBr);
453738c8a9a5SSteve French 	if (rc)
453838c8a9a5SSteve French 		return rc;
453938c8a9a5SSteve French 
454038c8a9a5SSteve French 	params = 2;	/* level */
454138c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
454238c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
454338c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
454438c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
454538c8a9a5SSteve French 	pSMB->Reserved = 0;
454638c8a9a5SSteve French 	pSMB->Flags = 0;
454738c8a9a5SSteve French 	pSMB->Timeout = 0;
454838c8a9a5SSteve French 	pSMB->Reserved2 = 0;
454938c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
455038c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
455138c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
455238c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
455338c8a9a5SSteve French 		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
455438c8a9a5SSteve French 	pSMB->DataCount = 0;
455538c8a9a5SSteve French 	pSMB->DataOffset = 0;
455638c8a9a5SSteve French 	pSMB->SetupCount = 1;
455738c8a9a5SSteve French 	pSMB->Reserved3 = 0;
455838c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
455938c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
456038c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
456138c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
456238c8a9a5SSteve French 
456338c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
456438c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
456538c8a9a5SSteve French 	if (rc) {
456638c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
456738c8a9a5SSteve French 	} else {		/* decode response */
456838c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
456938c8a9a5SSteve French 
457038c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 24)
457138c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
457238c8a9a5SSteve French 		else {
457338c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
457438c8a9a5SSteve French 
457538c8a9a5SSteve French 			response_data =
457638c8a9a5SSteve French 			    (FILE_SYSTEM_INFO
457738c8a9a5SSteve French 			     *) (((char *) &pSMBr->hdr.Protocol) +
457838c8a9a5SSteve French 				 data_offset);
457938c8a9a5SSteve French 			FSData->f_bsize =
458038c8a9a5SSteve French 			    le32_to_cpu(response_data->BytesPerSector) *
458138c8a9a5SSteve French 			    le32_to_cpu(response_data->
458238c8a9a5SSteve French 					SectorsPerAllocationUnit);
458338c8a9a5SSteve French 			/*
458438c8a9a5SSteve French 			 * much prefer larger but if server doesn't report
458538c8a9a5SSteve French 			 * a valid size than 4K is a reasonable minimum
458638c8a9a5SSteve French 			 */
458738c8a9a5SSteve French 			if (FSData->f_bsize < 512)
458838c8a9a5SSteve French 				FSData->f_bsize = 4096;
458938c8a9a5SSteve French 
459038c8a9a5SSteve French 			FSData->f_blocks =
459138c8a9a5SSteve French 			    le64_to_cpu(response_data->TotalAllocationUnits);
459238c8a9a5SSteve French 			FSData->f_bfree = FSData->f_bavail =
459338c8a9a5SSteve French 			    le64_to_cpu(response_data->FreeAllocationUnits);
459438c8a9a5SSteve French 			cifs_dbg(FYI, "Blocks: %lld  Free: %lld Block size %ld\n",
459538c8a9a5SSteve French 				 (unsigned long long)FSData->f_blocks,
459638c8a9a5SSteve French 				 (unsigned long long)FSData->f_bfree,
459738c8a9a5SSteve French 				 FSData->f_bsize);
459838c8a9a5SSteve French 		}
459938c8a9a5SSteve French 	}
460038c8a9a5SSteve French 	cifs_buf_release(pSMB);
460138c8a9a5SSteve French 
460238c8a9a5SSteve French 	if (rc == -EAGAIN)
460338c8a9a5SSteve French 		goto QFSInfoRetry;
460438c8a9a5SSteve French 
460538c8a9a5SSteve French 	return rc;
460638c8a9a5SSteve French }
460738c8a9a5SSteve French 
460838c8a9a5SSteve French int
CIFSSMBQFSAttributeInfo(const unsigned int xid,struct cifs_tcon * tcon)460938c8a9a5SSteve French CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
461038c8a9a5SSteve French {
461138c8a9a5SSteve French /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
461238c8a9a5SSteve French 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
461338c8a9a5SSteve French 	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
461438c8a9a5SSteve French 	FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
461538c8a9a5SSteve French 	int rc = 0;
461638c8a9a5SSteve French 	int bytes_returned = 0;
461738c8a9a5SSteve French 	__u16 params, byte_count;
461838c8a9a5SSteve French 
461938c8a9a5SSteve French 	cifs_dbg(FYI, "In QFSAttributeInfo\n");
462038c8a9a5SSteve French QFSAttributeRetry:
462138c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
462238c8a9a5SSteve French 		      (void **) &pSMBr);
462338c8a9a5SSteve French 	if (rc)
462438c8a9a5SSteve French 		return rc;
462538c8a9a5SSteve French 
462638c8a9a5SSteve French 	params = 2;	/* level */
462738c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
462838c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
462938c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
463038c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
463138c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
463238c8a9a5SSteve French 	pSMB->Reserved = 0;
463338c8a9a5SSteve French 	pSMB->Flags = 0;
463438c8a9a5SSteve French 	pSMB->Timeout = 0;
463538c8a9a5SSteve French 	pSMB->Reserved2 = 0;
463638c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
463738c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
463838c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
463938c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
464038c8a9a5SSteve French 		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
464138c8a9a5SSteve French 	pSMB->DataCount = 0;
464238c8a9a5SSteve French 	pSMB->DataOffset = 0;
464338c8a9a5SSteve French 	pSMB->SetupCount = 1;
464438c8a9a5SSteve French 	pSMB->Reserved3 = 0;
464538c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
464638c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
464738c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
464838c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
464938c8a9a5SSteve French 
465038c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
465138c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
465238c8a9a5SSteve French 	if (rc) {
465338c8a9a5SSteve French 		cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
465438c8a9a5SSteve French 	} else {		/* decode response */
465538c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
465638c8a9a5SSteve French 
465738c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 13) {
465838c8a9a5SSteve French 			/* BB also check if enough bytes returned */
465938c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
466038c8a9a5SSteve French 		} else {
466138c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
466238c8a9a5SSteve French 			response_data =
466338c8a9a5SSteve French 			    (FILE_SYSTEM_ATTRIBUTE_INFO
466438c8a9a5SSteve French 			     *) (((char *) &pSMBr->hdr.Protocol) +
466538c8a9a5SSteve French 				 data_offset);
466638c8a9a5SSteve French 			memcpy(&tcon->fsAttrInfo, response_data,
466738c8a9a5SSteve French 			       sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
466838c8a9a5SSteve French 		}
466938c8a9a5SSteve French 	}
467038c8a9a5SSteve French 	cifs_buf_release(pSMB);
467138c8a9a5SSteve French 
467238c8a9a5SSteve French 	if (rc == -EAGAIN)
467338c8a9a5SSteve French 		goto QFSAttributeRetry;
467438c8a9a5SSteve French 
467538c8a9a5SSteve French 	return rc;
467638c8a9a5SSteve French }
467738c8a9a5SSteve French 
467838c8a9a5SSteve French int
CIFSSMBQFSDeviceInfo(const unsigned int xid,struct cifs_tcon * tcon)467938c8a9a5SSteve French CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
468038c8a9a5SSteve French {
468138c8a9a5SSteve French /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
468238c8a9a5SSteve French 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
468338c8a9a5SSteve French 	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
468438c8a9a5SSteve French 	FILE_SYSTEM_DEVICE_INFO *response_data;
468538c8a9a5SSteve French 	int rc = 0;
468638c8a9a5SSteve French 	int bytes_returned = 0;
468738c8a9a5SSteve French 	__u16 params, byte_count;
468838c8a9a5SSteve French 
468938c8a9a5SSteve French 	cifs_dbg(FYI, "In QFSDeviceInfo\n");
469038c8a9a5SSteve French QFSDeviceRetry:
469138c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
469238c8a9a5SSteve French 		      (void **) &pSMBr);
469338c8a9a5SSteve French 	if (rc)
469438c8a9a5SSteve French 		return rc;
469538c8a9a5SSteve French 
469638c8a9a5SSteve French 	params = 2;	/* level */
469738c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
469838c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
469938c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
470038c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
470138c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
470238c8a9a5SSteve French 	pSMB->Reserved = 0;
470338c8a9a5SSteve French 	pSMB->Flags = 0;
470438c8a9a5SSteve French 	pSMB->Timeout = 0;
470538c8a9a5SSteve French 	pSMB->Reserved2 = 0;
470638c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
470738c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
470838c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
470938c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
471038c8a9a5SSteve French 		struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
471138c8a9a5SSteve French 
471238c8a9a5SSteve French 	pSMB->DataCount = 0;
471338c8a9a5SSteve French 	pSMB->DataOffset = 0;
471438c8a9a5SSteve French 	pSMB->SetupCount = 1;
471538c8a9a5SSteve French 	pSMB->Reserved3 = 0;
471638c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
471738c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
471838c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
471938c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
472038c8a9a5SSteve French 
472138c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
472238c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
472338c8a9a5SSteve French 	if (rc) {
472438c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
472538c8a9a5SSteve French 	} else {		/* decode response */
472638c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
472738c8a9a5SSteve French 
472838c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) <
472938c8a9a5SSteve French 			  sizeof(FILE_SYSTEM_DEVICE_INFO))
473038c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
473138c8a9a5SSteve French 		else {
473238c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
473338c8a9a5SSteve French 			response_data =
473438c8a9a5SSteve French 			    (FILE_SYSTEM_DEVICE_INFO *)
473538c8a9a5SSteve French 				(((char *) &pSMBr->hdr.Protocol) +
473638c8a9a5SSteve French 				 data_offset);
473738c8a9a5SSteve French 			memcpy(&tcon->fsDevInfo, response_data,
473838c8a9a5SSteve French 			       sizeof(FILE_SYSTEM_DEVICE_INFO));
473938c8a9a5SSteve French 		}
474038c8a9a5SSteve French 	}
474138c8a9a5SSteve French 	cifs_buf_release(pSMB);
474238c8a9a5SSteve French 
474338c8a9a5SSteve French 	if (rc == -EAGAIN)
474438c8a9a5SSteve French 		goto QFSDeviceRetry;
474538c8a9a5SSteve French 
474638c8a9a5SSteve French 	return rc;
474738c8a9a5SSteve French }
474838c8a9a5SSteve French 
474938c8a9a5SSteve French int
CIFSSMBQFSUnixInfo(const unsigned int xid,struct cifs_tcon * tcon)475038c8a9a5SSteve French CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
475138c8a9a5SSteve French {
475238c8a9a5SSteve French /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
475338c8a9a5SSteve French 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
475438c8a9a5SSteve French 	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
475538c8a9a5SSteve French 	FILE_SYSTEM_UNIX_INFO *response_data;
475638c8a9a5SSteve French 	int rc = 0;
475738c8a9a5SSteve French 	int bytes_returned = 0;
475838c8a9a5SSteve French 	__u16 params, byte_count;
475938c8a9a5SSteve French 
476038c8a9a5SSteve French 	cifs_dbg(FYI, "In QFSUnixInfo\n");
476138c8a9a5SSteve French QFSUnixRetry:
476238c8a9a5SSteve French 	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
476338c8a9a5SSteve French 				   (void **) &pSMB, (void **) &pSMBr);
476438c8a9a5SSteve French 	if (rc)
476538c8a9a5SSteve French 		return rc;
476638c8a9a5SSteve French 
476738c8a9a5SSteve French 	params = 2;	/* level */
476838c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
476938c8a9a5SSteve French 	pSMB->DataCount = 0;
477038c8a9a5SSteve French 	pSMB->DataOffset = 0;
477138c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
477238c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
477338c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(100);
477438c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
477538c8a9a5SSteve French 	pSMB->Reserved = 0;
477638c8a9a5SSteve French 	pSMB->Flags = 0;
477738c8a9a5SSteve French 	pSMB->Timeout = 0;
477838c8a9a5SSteve French 	pSMB->Reserved2 = 0;
477938c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
478038c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
478138c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
478238c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
478338c8a9a5SSteve French 			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
478438c8a9a5SSteve French 	pSMB->SetupCount = 1;
478538c8a9a5SSteve French 	pSMB->Reserved3 = 0;
478638c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
478738c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
478838c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
478938c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
479038c8a9a5SSteve French 
479138c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
479238c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
479338c8a9a5SSteve French 	if (rc) {
479438c8a9a5SSteve French 		cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
479538c8a9a5SSteve French 	} else {		/* decode response */
479638c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
479738c8a9a5SSteve French 
479838c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 13) {
479938c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
480038c8a9a5SSteve French 		} else {
480138c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
480238c8a9a5SSteve French 			response_data =
480338c8a9a5SSteve French 			    (FILE_SYSTEM_UNIX_INFO
480438c8a9a5SSteve French 			     *) (((char *) &pSMBr->hdr.Protocol) +
480538c8a9a5SSteve French 				 data_offset);
480638c8a9a5SSteve French 			memcpy(&tcon->fsUnixInfo, response_data,
480738c8a9a5SSteve French 			       sizeof(FILE_SYSTEM_UNIX_INFO));
480838c8a9a5SSteve French 		}
480938c8a9a5SSteve French 	}
481038c8a9a5SSteve French 	cifs_buf_release(pSMB);
481138c8a9a5SSteve French 
481238c8a9a5SSteve French 	if (rc == -EAGAIN)
481338c8a9a5SSteve French 		goto QFSUnixRetry;
481438c8a9a5SSteve French 
481538c8a9a5SSteve French 
481638c8a9a5SSteve French 	return rc;
481738c8a9a5SSteve French }
481838c8a9a5SSteve French 
481938c8a9a5SSteve French int
CIFSSMBSetFSUnixInfo(const unsigned int xid,struct cifs_tcon * tcon,__u64 cap)482038c8a9a5SSteve French CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
482138c8a9a5SSteve French {
482238c8a9a5SSteve French /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
482338c8a9a5SSteve French 	TRANSACTION2_SETFSI_REQ *pSMB = NULL;
482438c8a9a5SSteve French 	TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
482538c8a9a5SSteve French 	int rc = 0;
482638c8a9a5SSteve French 	int bytes_returned = 0;
482738c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count;
482838c8a9a5SSteve French 
482938c8a9a5SSteve French 	cifs_dbg(FYI, "In SETFSUnixInfo\n");
483038c8a9a5SSteve French SETFSUnixRetry:
483138c8a9a5SSteve French 	/* BB switch to small buf init to save memory */
483238c8a9a5SSteve French 	rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
483338c8a9a5SSteve French 					(void **) &pSMB, (void **) &pSMBr);
483438c8a9a5SSteve French 	if (rc)
483538c8a9a5SSteve French 		return rc;
483638c8a9a5SSteve French 
483738c8a9a5SSteve French 	params = 4;	/* 2 bytes zero followed by info level. */
483838c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
483938c8a9a5SSteve French 	pSMB->Reserved = 0;
484038c8a9a5SSteve French 	pSMB->Flags = 0;
484138c8a9a5SSteve French 	pSMB->Timeout = 0;
484238c8a9a5SSteve French 	pSMB->Reserved2 = 0;
484338c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
484438c8a9a5SSteve French 				- 4;
484538c8a9a5SSteve French 	offset = param_offset + params;
484638c8a9a5SSteve French 
484738c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(4);
484838c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
484938c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(100);
485038c8a9a5SSteve French 	pSMB->SetupCount = 1;
485138c8a9a5SSteve French 	pSMB->Reserved3 = 0;
485238c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
485338c8a9a5SSteve French 	byte_count = 1 /* pad */ + params + 12;
485438c8a9a5SSteve French 
485538c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(12);
485638c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
485738c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
485838c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
485938c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
486038c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
486138c8a9a5SSteve French 
486238c8a9a5SSteve French 	/* Params. */
486338c8a9a5SSteve French 	pSMB->FileNum = 0;
486438c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
486538c8a9a5SSteve French 
486638c8a9a5SSteve French 	/* Data. */
486738c8a9a5SSteve French 	pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
486838c8a9a5SSteve French 	pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
486938c8a9a5SSteve French 	pSMB->ClientUnixCap = cpu_to_le64(cap);
487038c8a9a5SSteve French 
487138c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
487238c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
487338c8a9a5SSteve French 
487438c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
487538c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
487638c8a9a5SSteve French 	if (rc) {
487738c8a9a5SSteve French 		cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
487838c8a9a5SSteve French 	} else {		/* decode response */
487938c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
488038c8a9a5SSteve French 		if (rc)
488138c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
488238c8a9a5SSteve French 	}
488338c8a9a5SSteve French 	cifs_buf_release(pSMB);
488438c8a9a5SSteve French 
488538c8a9a5SSteve French 	if (rc == -EAGAIN)
488638c8a9a5SSteve French 		goto SETFSUnixRetry;
488738c8a9a5SSteve French 
488838c8a9a5SSteve French 	return rc;
488938c8a9a5SSteve French }
489038c8a9a5SSteve French 
489138c8a9a5SSteve French 
489238c8a9a5SSteve French 
489338c8a9a5SSteve French int
CIFSSMBQFSPosixInfo(const unsigned int xid,struct cifs_tcon * tcon,struct kstatfs * FSData)489438c8a9a5SSteve French CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
489538c8a9a5SSteve French 		   struct kstatfs *FSData)
489638c8a9a5SSteve French {
489738c8a9a5SSteve French /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
489838c8a9a5SSteve French 	TRANSACTION2_QFSI_REQ *pSMB = NULL;
489938c8a9a5SSteve French 	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
490038c8a9a5SSteve French 	FILE_SYSTEM_POSIX_INFO *response_data;
490138c8a9a5SSteve French 	int rc = 0;
490238c8a9a5SSteve French 	int bytes_returned = 0;
490338c8a9a5SSteve French 	__u16 params, byte_count;
490438c8a9a5SSteve French 
490538c8a9a5SSteve French 	cifs_dbg(FYI, "In QFSPosixInfo\n");
490638c8a9a5SSteve French QFSPosixRetry:
490738c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
490838c8a9a5SSteve French 		      (void **) &pSMBr);
490938c8a9a5SSteve French 	if (rc)
491038c8a9a5SSteve French 		return rc;
491138c8a9a5SSteve French 
491238c8a9a5SSteve French 	params = 2;	/* level */
491338c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
491438c8a9a5SSteve French 	pSMB->DataCount = 0;
491538c8a9a5SSteve French 	pSMB->DataOffset = 0;
491638c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
491738c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
491838c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(100);
491938c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
492038c8a9a5SSteve French 	pSMB->Reserved = 0;
492138c8a9a5SSteve French 	pSMB->Flags = 0;
492238c8a9a5SSteve French 	pSMB->Timeout = 0;
492338c8a9a5SSteve French 	pSMB->Reserved2 = 0;
492438c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
492538c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
492638c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
492738c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
492838c8a9a5SSteve French 			smb_com_transaction2_qfsi_req, InformationLevel) - 4);
492938c8a9a5SSteve French 	pSMB->SetupCount = 1;
493038c8a9a5SSteve French 	pSMB->Reserved3 = 0;
493138c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
493238c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
493338c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
493438c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
493538c8a9a5SSteve French 
493638c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
493738c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
493838c8a9a5SSteve French 	if (rc) {
493938c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
494038c8a9a5SSteve French 	} else {		/* decode response */
494138c8a9a5SSteve French 		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
494238c8a9a5SSteve French 
494338c8a9a5SSteve French 		if (rc || get_bcc(&pSMBr->hdr) < 13) {
494438c8a9a5SSteve French 			rc = -EIO;	/* bad smb */
494538c8a9a5SSteve French 		} else {
494638c8a9a5SSteve French 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
494738c8a9a5SSteve French 			response_data =
494838c8a9a5SSteve French 			    (FILE_SYSTEM_POSIX_INFO
494938c8a9a5SSteve French 			     *) (((char *) &pSMBr->hdr.Protocol) +
495038c8a9a5SSteve French 				 data_offset);
495138c8a9a5SSteve French 			FSData->f_bsize =
495238c8a9a5SSteve French 					le32_to_cpu(response_data->BlockSize);
495338c8a9a5SSteve French 			/*
495438c8a9a5SSteve French 			 * much prefer larger but if server doesn't report
495538c8a9a5SSteve French 			 * a valid size than 4K is a reasonable minimum
495638c8a9a5SSteve French 			 */
495738c8a9a5SSteve French 			if (FSData->f_bsize < 512)
495838c8a9a5SSteve French 				FSData->f_bsize = 4096;
495938c8a9a5SSteve French 
496038c8a9a5SSteve French 			FSData->f_blocks =
496138c8a9a5SSteve French 					le64_to_cpu(response_data->TotalBlocks);
496238c8a9a5SSteve French 			FSData->f_bfree =
496338c8a9a5SSteve French 			    le64_to_cpu(response_data->BlocksAvail);
496438c8a9a5SSteve French 			if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
496538c8a9a5SSteve French 				FSData->f_bavail = FSData->f_bfree;
496638c8a9a5SSteve French 			} else {
496738c8a9a5SSteve French 				FSData->f_bavail =
496838c8a9a5SSteve French 				    le64_to_cpu(response_data->UserBlocksAvail);
496938c8a9a5SSteve French 			}
497038c8a9a5SSteve French 			if (response_data->TotalFileNodes != cpu_to_le64(-1))
497138c8a9a5SSteve French 				FSData->f_files =
497238c8a9a5SSteve French 				     le64_to_cpu(response_data->TotalFileNodes);
497338c8a9a5SSteve French 			if (response_data->FreeFileNodes != cpu_to_le64(-1))
497438c8a9a5SSteve French 				FSData->f_ffree =
497538c8a9a5SSteve French 				      le64_to_cpu(response_data->FreeFileNodes);
497638c8a9a5SSteve French 		}
497738c8a9a5SSteve French 	}
497838c8a9a5SSteve French 	cifs_buf_release(pSMB);
497938c8a9a5SSteve French 
498038c8a9a5SSteve French 	if (rc == -EAGAIN)
498138c8a9a5SSteve French 		goto QFSPosixRetry;
498238c8a9a5SSteve French 
498338c8a9a5SSteve French 	return rc;
498438c8a9a5SSteve French }
498538c8a9a5SSteve French 
498638c8a9a5SSteve French 
498738c8a9a5SSteve French /*
498838c8a9a5SSteve French  * We can not use write of zero bytes trick to set file size due to need for
498938c8a9a5SSteve French  * large file support. Also note that this SetPathInfo is preferred to
499038c8a9a5SSteve French  * SetFileInfo based method in next routine which is only needed to work around
499138c8a9a5SSteve French  * a sharing violation bugin Samba which this routine can run into.
499238c8a9a5SSteve French  */
499338c8a9a5SSteve French int
CIFSSMBSetEOF(const unsigned int xid,struct cifs_tcon * tcon,const char * file_name,__u64 size,struct cifs_sb_info * cifs_sb,bool set_allocation,struct dentry * dentry)499438c8a9a5SSteve French CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
499538c8a9a5SSteve French 	      const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
4996f93d145fSMeetakshi Setiya 	      bool set_allocation, struct dentry *dentry)
499738c8a9a5SSteve French {
499838c8a9a5SSteve French 	struct smb_com_transaction2_spi_req *pSMB = NULL;
499938c8a9a5SSteve French 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
500038c8a9a5SSteve French 	struct file_end_of_file_info *parm_data;
500138c8a9a5SSteve French 	int name_len;
500238c8a9a5SSteve French 	int rc = 0;
500338c8a9a5SSteve French 	int bytes_returned = 0;
500438c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
500538c8a9a5SSteve French 
500638c8a9a5SSteve French 	__u16 params, byte_count, data_count, param_offset, offset;
500738c8a9a5SSteve French 
500838c8a9a5SSteve French 	cifs_dbg(FYI, "In SetEOF\n");
500938c8a9a5SSteve French SetEOFRetry:
501038c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
501138c8a9a5SSteve French 		      (void **) &pSMBr);
501238c8a9a5SSteve French 	if (rc)
501338c8a9a5SSteve French 		return rc;
501438c8a9a5SSteve French 
501538c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
501638c8a9a5SSteve French 		name_len =
501738c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
501838c8a9a5SSteve French 				       PATH_MAX, cifs_sb->local_nls, remap);
501938c8a9a5SSteve French 		name_len++;	/* trailing null */
502038c8a9a5SSteve French 		name_len *= 2;
502138c8a9a5SSteve French 	} else {
502238c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, file_name);
502338c8a9a5SSteve French 	}
502438c8a9a5SSteve French 	params = 6 + name_len;
502538c8a9a5SSteve French 	data_count = sizeof(struct file_end_of_file_info);
502638c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
502738c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(4100);
502838c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
502938c8a9a5SSteve French 	pSMB->Reserved = 0;
503038c8a9a5SSteve French 	pSMB->Flags = 0;
503138c8a9a5SSteve French 	pSMB->Timeout = 0;
503238c8a9a5SSteve French 	pSMB->Reserved2 = 0;
503338c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
503438c8a9a5SSteve French 				InformationLevel) - 4;
503538c8a9a5SSteve French 	offset = param_offset + params;
503638c8a9a5SSteve French 	if (set_allocation) {
503738c8a9a5SSteve French 		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
503838c8a9a5SSteve French 			pSMB->InformationLevel =
503938c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
504038c8a9a5SSteve French 		else
504138c8a9a5SSteve French 			pSMB->InformationLevel =
504238c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
504338c8a9a5SSteve French 	} else /* Set File Size */  {
504438c8a9a5SSteve French 	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
504538c8a9a5SSteve French 		    pSMB->InformationLevel =
504638c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
504738c8a9a5SSteve French 	    else
504838c8a9a5SSteve French 		    pSMB->InformationLevel =
504938c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
505038c8a9a5SSteve French 	}
505138c8a9a5SSteve French 
505238c8a9a5SSteve French 	parm_data =
505338c8a9a5SSteve French 	    (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
505438c8a9a5SSteve French 				       offset);
505538c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
505638c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
505738c8a9a5SSteve French 	pSMB->SetupCount = 1;
505838c8a9a5SSteve French 	pSMB->Reserved3 = 0;
505938c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
506038c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + data_count;
506138c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(data_count);
506238c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
506338c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
506438c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
506538c8a9a5SSteve French 	pSMB->Reserved4 = 0;
506638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
506738c8a9a5SSteve French 	parm_data->FileSize = cpu_to_le64(size);
506838c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
506938c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
507038c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
507138c8a9a5SSteve French 	if (rc)
507238c8a9a5SSteve French 		cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
507338c8a9a5SSteve French 
507438c8a9a5SSteve French 	cifs_buf_release(pSMB);
507538c8a9a5SSteve French 
507638c8a9a5SSteve French 	if (rc == -EAGAIN)
507738c8a9a5SSteve French 		goto SetEOFRetry;
507838c8a9a5SSteve French 
507938c8a9a5SSteve French 	return rc;
508038c8a9a5SSteve French }
508138c8a9a5SSteve French 
508238c8a9a5SSteve French int
CIFSSMBSetFileSize(const unsigned int xid,struct cifs_tcon * tcon,struct cifsFileInfo * cfile,__u64 size,bool set_allocation)508338c8a9a5SSteve French CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
508438c8a9a5SSteve French 		   struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
508538c8a9a5SSteve French {
508638c8a9a5SSteve French 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
508738c8a9a5SSteve French 	struct file_end_of_file_info *parm_data;
508838c8a9a5SSteve French 	int rc = 0;
508938c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count, count;
509038c8a9a5SSteve French 
509138c8a9a5SSteve French 	cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
509238c8a9a5SSteve French 		 (long long)size);
509338c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
509438c8a9a5SSteve French 
509538c8a9a5SSteve French 	if (rc)
509638c8a9a5SSteve French 		return rc;
509738c8a9a5SSteve French 
509838c8a9a5SSteve French 	pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
509938c8a9a5SSteve French 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
510038c8a9a5SSteve French 
510138c8a9a5SSteve French 	params = 6;
510238c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
510338c8a9a5SSteve French 	pSMB->Reserved = 0;
510438c8a9a5SSteve French 	pSMB->Flags = 0;
510538c8a9a5SSteve French 	pSMB->Timeout = 0;
510638c8a9a5SSteve French 	pSMB->Reserved2 = 0;
510738c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
510838c8a9a5SSteve French 	offset = param_offset + params;
510938c8a9a5SSteve French 
511038c8a9a5SSteve French 	count = sizeof(struct file_end_of_file_info);
511138c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
511238c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
511338c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
511438c8a9a5SSteve French 	pSMB->SetupCount = 1;
511538c8a9a5SSteve French 	pSMB->Reserved3 = 0;
511638c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
511738c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
511838c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
511938c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
512038c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
512138c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
512238c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
512338c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
512438c8a9a5SSteve French 	parm_data =
512538c8a9a5SSteve French 		(struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
512638c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
512738c8a9a5SSteve French 	parm_data->FileSize = cpu_to_le64(size);
512838c8a9a5SSteve French 	pSMB->Fid = cfile->fid.netfid;
512938c8a9a5SSteve French 	if (set_allocation) {
513038c8a9a5SSteve French 		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
513138c8a9a5SSteve French 			pSMB->InformationLevel =
513238c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
513338c8a9a5SSteve French 		else
513438c8a9a5SSteve French 			pSMB->InformationLevel =
513538c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
513638c8a9a5SSteve French 	} else /* Set File Size */  {
513738c8a9a5SSteve French 	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
513838c8a9a5SSteve French 		    pSMB->InformationLevel =
513938c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
514038c8a9a5SSteve French 	    else
514138c8a9a5SSteve French 		    pSMB->InformationLevel =
514238c8a9a5SSteve French 				cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
514338c8a9a5SSteve French 	}
514438c8a9a5SSteve French 	pSMB->Reserved4 = 0;
514538c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
514638c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
514738c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
514838c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
514938c8a9a5SSteve French 	if (rc) {
515038c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
515138c8a9a5SSteve French 			 rc);
515238c8a9a5SSteve French 	}
515338c8a9a5SSteve French 
515438c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
515538c8a9a5SSteve French 		since file handle passed in no longer valid */
515638c8a9a5SSteve French 
515738c8a9a5SSteve French 	return rc;
515838c8a9a5SSteve French }
515938c8a9a5SSteve French 
516038c8a9a5SSteve French /* Some legacy servers such as NT4 require that the file times be set on
516138c8a9a5SSteve French    an open handle, rather than by pathname - this is awkward due to
516238c8a9a5SSteve French    potential access conflicts on the open, but it is unavoidable for these
516338c8a9a5SSteve French    old servers since the only other choice is to go from 100 nanosecond DCE
516438c8a9a5SSteve French    time and resort to the original setpathinfo level which takes the ancient
516538c8a9a5SSteve French    DOS time format with 2 second granularity */
516638c8a9a5SSteve French int
CIFSSMBSetFileInfo(const unsigned int xid,struct cifs_tcon * tcon,const FILE_BASIC_INFO * data,__u16 fid,__u32 pid_of_opener)516738c8a9a5SSteve French CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
516838c8a9a5SSteve French 		    const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
516938c8a9a5SSteve French {
517038c8a9a5SSteve French 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
517138c8a9a5SSteve French 	char *data_offset;
517238c8a9a5SSteve French 	int rc = 0;
517338c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count, count;
517438c8a9a5SSteve French 
517538c8a9a5SSteve French 	cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
517638c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
517738c8a9a5SSteve French 
517838c8a9a5SSteve French 	if (rc)
517938c8a9a5SSteve French 		return rc;
518038c8a9a5SSteve French 
518138c8a9a5SSteve French 	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
518238c8a9a5SSteve French 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
518338c8a9a5SSteve French 
518438c8a9a5SSteve French 	params = 6;
518538c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
518638c8a9a5SSteve French 	pSMB->Reserved = 0;
518738c8a9a5SSteve French 	pSMB->Flags = 0;
518838c8a9a5SSteve French 	pSMB->Timeout = 0;
518938c8a9a5SSteve French 	pSMB->Reserved2 = 0;
519038c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
519138c8a9a5SSteve French 	offset = param_offset + params;
519238c8a9a5SSteve French 
519338c8a9a5SSteve French 	data_offset = (char *)pSMB +
519438c8a9a5SSteve French 			offsetof(struct smb_hdr, Protocol) + offset;
519538c8a9a5SSteve French 
519638c8a9a5SSteve French 	count = sizeof(FILE_BASIC_INFO);
519738c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
519838c8a9a5SSteve French 	/* BB find max SMB PDU from sess */
519938c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
520038c8a9a5SSteve French 	pSMB->SetupCount = 1;
520138c8a9a5SSteve French 	pSMB->Reserved3 = 0;
520238c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
520338c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
520438c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
520538c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
520638c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
520738c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
520838c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
520938c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
521038c8a9a5SSteve French 	pSMB->Fid = fid;
521138c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
521238c8a9a5SSteve French 		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
521338c8a9a5SSteve French 	else
521438c8a9a5SSteve French 		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
521538c8a9a5SSteve French 	pSMB->Reserved4 = 0;
521638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
521738c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
521838c8a9a5SSteve French 	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
521938c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
522038c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
522138c8a9a5SSteve French 	if (rc)
522238c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
522338c8a9a5SSteve French 			 rc);
522438c8a9a5SSteve French 
522538c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
522638c8a9a5SSteve French 		since file handle passed in no longer valid */
522738c8a9a5SSteve French 
522838c8a9a5SSteve French 	return rc;
522938c8a9a5SSteve French }
523038c8a9a5SSteve French 
523138c8a9a5SSteve French int
CIFSSMBSetFileDisposition(const unsigned int xid,struct cifs_tcon * tcon,bool delete_file,__u16 fid,__u32 pid_of_opener)523238c8a9a5SSteve French CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
523338c8a9a5SSteve French 			  bool delete_file, __u16 fid, __u32 pid_of_opener)
523438c8a9a5SSteve French {
523538c8a9a5SSteve French 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
523638c8a9a5SSteve French 	char *data_offset;
523738c8a9a5SSteve French 	int rc = 0;
523838c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count, count;
523938c8a9a5SSteve French 
524038c8a9a5SSteve French 	cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
524138c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
524238c8a9a5SSteve French 
524338c8a9a5SSteve French 	if (rc)
524438c8a9a5SSteve French 		return rc;
524538c8a9a5SSteve French 
524638c8a9a5SSteve French 	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
524738c8a9a5SSteve French 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
524838c8a9a5SSteve French 
524938c8a9a5SSteve French 	params = 6;
525038c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
525138c8a9a5SSteve French 	pSMB->Reserved = 0;
525238c8a9a5SSteve French 	pSMB->Flags = 0;
525338c8a9a5SSteve French 	pSMB->Timeout = 0;
525438c8a9a5SSteve French 	pSMB->Reserved2 = 0;
525538c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
525638c8a9a5SSteve French 	offset = param_offset + params;
525738c8a9a5SSteve French 
525838c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
525938c8a9a5SSteve French 	data_offset = (char *)(pSMB) + offset + 4;
526038c8a9a5SSteve French 
526138c8a9a5SSteve French 	count = 1;
526238c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
526338c8a9a5SSteve French 	/* BB find max SMB PDU from sess */
526438c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
526538c8a9a5SSteve French 	pSMB->SetupCount = 1;
526638c8a9a5SSteve French 	pSMB->Reserved3 = 0;
526738c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
526838c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
526938c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
527038c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
527138c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
527238c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
527338c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
527438c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
527538c8a9a5SSteve French 	pSMB->Fid = fid;
527638c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
527738c8a9a5SSteve French 	pSMB->Reserved4 = 0;
527838c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
527938c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
528038c8a9a5SSteve French 	*data_offset = delete_file ? 1 : 0;
528138c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
528238c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
528338c8a9a5SSteve French 	if (rc)
528438c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
528538c8a9a5SSteve French 
528638c8a9a5SSteve French 	return rc;
528738c8a9a5SSteve French }
528838c8a9a5SSteve French 
528938c8a9a5SSteve French static int
CIFSSMBSetPathInfoFB(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const FILE_BASIC_INFO * data,const struct nls_table * nls_codepage,struct cifs_sb_info * cifs_sb)529038c8a9a5SSteve French CIFSSMBSetPathInfoFB(const unsigned int xid, struct cifs_tcon *tcon,
529138c8a9a5SSteve French 		     const char *fileName, const FILE_BASIC_INFO *data,
529238c8a9a5SSteve French 		     const struct nls_table *nls_codepage,
529338c8a9a5SSteve French 		     struct cifs_sb_info *cifs_sb)
529438c8a9a5SSteve French {
529538c8a9a5SSteve French 	int oplock = 0;
529638c8a9a5SSteve French 	struct cifs_open_parms oparms;
529738c8a9a5SSteve French 	struct cifs_fid fid;
529838c8a9a5SSteve French 	int rc;
529938c8a9a5SSteve French 
530038c8a9a5SSteve French 	oparms = (struct cifs_open_parms) {
530138c8a9a5SSteve French 		.tcon = tcon,
530238c8a9a5SSteve French 		.cifs_sb = cifs_sb,
530338c8a9a5SSteve French 		.desired_access = GENERIC_WRITE,
530438c8a9a5SSteve French 		.create_options = cifs_create_options(cifs_sb, 0),
530538c8a9a5SSteve French 		.disposition = FILE_OPEN,
530638c8a9a5SSteve French 		.path = fileName,
530738c8a9a5SSteve French 		.fid = &fid,
530838c8a9a5SSteve French 	};
530938c8a9a5SSteve French 
531038c8a9a5SSteve French 	rc = CIFS_open(xid, &oparms, &oplock, NULL);
531138c8a9a5SSteve French 	if (rc)
531238c8a9a5SSteve French 		goto out;
531338c8a9a5SSteve French 
531438c8a9a5SSteve French 	rc = CIFSSMBSetFileInfo(xid, tcon, data, fid.netfid, current->tgid);
531538c8a9a5SSteve French 	CIFSSMBClose(xid, tcon, fid.netfid);
531638c8a9a5SSteve French out:
531738c8a9a5SSteve French 
531838c8a9a5SSteve French 	return rc;
531938c8a9a5SSteve French }
532038c8a9a5SSteve French 
532138c8a9a5SSteve French int
CIFSSMBSetPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const FILE_BASIC_INFO * data,const struct nls_table * nls_codepage,struct cifs_sb_info * cifs_sb)532238c8a9a5SSteve French CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
532338c8a9a5SSteve French 		   const char *fileName, const FILE_BASIC_INFO *data,
532438c8a9a5SSteve French 		   const struct nls_table *nls_codepage,
532538c8a9a5SSteve French 		     struct cifs_sb_info *cifs_sb)
532638c8a9a5SSteve French {
532738c8a9a5SSteve French 	TRANSACTION2_SPI_REQ *pSMB = NULL;
532838c8a9a5SSteve French 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
532938c8a9a5SSteve French 	int name_len;
533038c8a9a5SSteve French 	int rc = 0;
533138c8a9a5SSteve French 	int bytes_returned = 0;
533238c8a9a5SSteve French 	char *data_offset;
533338c8a9a5SSteve French 	__u16 params, param_offset, offset, byte_count, count;
533438c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
533538c8a9a5SSteve French 
533638c8a9a5SSteve French 	cifs_dbg(FYI, "In SetTimes\n");
533738c8a9a5SSteve French 
533838c8a9a5SSteve French SetTimesRetry:
533938c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
534038c8a9a5SSteve French 		      (void **) &pSMBr);
534138c8a9a5SSteve French 	if (rc)
534238c8a9a5SSteve French 		return rc;
534338c8a9a5SSteve French 
534438c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
534538c8a9a5SSteve French 		name_len =
534638c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
534738c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
534838c8a9a5SSteve French 		name_len++;	/* trailing null */
534938c8a9a5SSteve French 		name_len *= 2;
535038c8a9a5SSteve French 	} else {
535138c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, fileName);
535238c8a9a5SSteve French 	}
535338c8a9a5SSteve French 
535438c8a9a5SSteve French 	params = 6 + name_len;
535538c8a9a5SSteve French 	count = sizeof(FILE_BASIC_INFO);
535638c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
535738c8a9a5SSteve French 	/* BB find max SMB PDU from sess structure BB */
535838c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
535938c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
536038c8a9a5SSteve French 	pSMB->Reserved = 0;
536138c8a9a5SSteve French 	pSMB->Flags = 0;
536238c8a9a5SSteve French 	pSMB->Timeout = 0;
536338c8a9a5SSteve French 	pSMB->Reserved2 = 0;
536438c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
536538c8a9a5SSteve French 				InformationLevel) - 4;
536638c8a9a5SSteve French 	offset = param_offset + params;
536738c8a9a5SSteve French 	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
536838c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
536938c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
537038c8a9a5SSteve French 	pSMB->SetupCount = 1;
537138c8a9a5SSteve French 	pSMB->Reserved3 = 0;
537238c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
537338c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
537438c8a9a5SSteve French 
537538c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
537638c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
537738c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
537838c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
537938c8a9a5SSteve French 	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
538038c8a9a5SSteve French 		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
538138c8a9a5SSteve French 	else
538238c8a9a5SSteve French 		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
538338c8a9a5SSteve French 	pSMB->Reserved4 = 0;
538438c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
538538c8a9a5SSteve French 	memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
538638c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
538738c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
538838c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
538938c8a9a5SSteve French 	if (rc)
539038c8a9a5SSteve French 		cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
539138c8a9a5SSteve French 
539238c8a9a5SSteve French 	cifs_buf_release(pSMB);
539338c8a9a5SSteve French 
539438c8a9a5SSteve French 	if (rc == -EAGAIN)
539538c8a9a5SSteve French 		goto SetTimesRetry;
539638c8a9a5SSteve French 
539738c8a9a5SSteve French 	if (rc == -EOPNOTSUPP)
539838c8a9a5SSteve French 		return CIFSSMBSetPathInfoFB(xid, tcon, fileName, data,
539938c8a9a5SSteve French 					    nls_codepage, cifs_sb);
540038c8a9a5SSteve French 
540138c8a9a5SSteve French 	return rc;
540238c8a9a5SSteve French }
540338c8a9a5SSteve French 
540438c8a9a5SSteve French static void
cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO * data_offset,const struct cifs_unix_set_info_args * args)540538c8a9a5SSteve French cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
540638c8a9a5SSteve French 			const struct cifs_unix_set_info_args *args)
540738c8a9a5SSteve French {
540838c8a9a5SSteve French 	u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
540938c8a9a5SSteve French 	u64 mode = args->mode;
541038c8a9a5SSteve French 
541138c8a9a5SSteve French 	if (uid_valid(args->uid))
541238c8a9a5SSteve French 		uid = from_kuid(&init_user_ns, args->uid);
541338c8a9a5SSteve French 	if (gid_valid(args->gid))
541438c8a9a5SSteve French 		gid = from_kgid(&init_user_ns, args->gid);
541538c8a9a5SSteve French 
541638c8a9a5SSteve French 	/*
541738c8a9a5SSteve French 	 * Samba server ignores set of file size to zero due to bugs in some
541838c8a9a5SSteve French 	 * older clients, but we should be precise - we use SetFileSize to
541938c8a9a5SSteve French 	 * set file size and do not want to truncate file size to zero
542038c8a9a5SSteve French 	 * accidentally as happened on one Samba server beta by putting
542138c8a9a5SSteve French 	 * zero instead of -1 here
542238c8a9a5SSteve French 	 */
542338c8a9a5SSteve French 	data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
542438c8a9a5SSteve French 	data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
542538c8a9a5SSteve French 	data_offset->LastStatusChange = cpu_to_le64(args->ctime);
542638c8a9a5SSteve French 	data_offset->LastAccessTime = cpu_to_le64(args->atime);
542738c8a9a5SSteve French 	data_offset->LastModificationTime = cpu_to_le64(args->mtime);
542838c8a9a5SSteve French 	data_offset->Uid = cpu_to_le64(uid);
542938c8a9a5SSteve French 	data_offset->Gid = cpu_to_le64(gid);
543038c8a9a5SSteve French 	/* better to leave device as zero when it is  */
543138c8a9a5SSteve French 	data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
543238c8a9a5SSteve French 	data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
543338c8a9a5SSteve French 	data_offset->Permissions = cpu_to_le64(mode);
543438c8a9a5SSteve French 
543538c8a9a5SSteve French 	if (S_ISREG(mode))
543638c8a9a5SSteve French 		data_offset->Type = cpu_to_le32(UNIX_FILE);
543738c8a9a5SSteve French 	else if (S_ISDIR(mode))
543838c8a9a5SSteve French 		data_offset->Type = cpu_to_le32(UNIX_DIR);
543938c8a9a5SSteve French 	else if (S_ISLNK(mode))
544038c8a9a5SSteve French 		data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
544138c8a9a5SSteve French 	else if (S_ISCHR(mode))
544238c8a9a5SSteve French 		data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
544338c8a9a5SSteve French 	else if (S_ISBLK(mode))
544438c8a9a5SSteve French 		data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
544538c8a9a5SSteve French 	else if (S_ISFIFO(mode))
544638c8a9a5SSteve French 		data_offset->Type = cpu_to_le32(UNIX_FIFO);
544738c8a9a5SSteve French 	else if (S_ISSOCK(mode))
544838c8a9a5SSteve French 		data_offset->Type = cpu_to_le32(UNIX_SOCKET);
544938c8a9a5SSteve French }
545038c8a9a5SSteve French 
545138c8a9a5SSteve French int
CIFSSMBUnixSetFileInfo(const unsigned int xid,struct cifs_tcon * tcon,const struct cifs_unix_set_info_args * args,u16 fid,u32 pid_of_opener)545238c8a9a5SSteve French CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
545338c8a9a5SSteve French 		       const struct cifs_unix_set_info_args *args,
545438c8a9a5SSteve French 		       u16 fid, u32 pid_of_opener)
545538c8a9a5SSteve French {
545638c8a9a5SSteve French 	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
545738c8a9a5SSteve French 	char *data_offset;
545838c8a9a5SSteve French 	int rc = 0;
545938c8a9a5SSteve French 	u16 params, param_offset, offset, byte_count, count;
546038c8a9a5SSteve French 
546138c8a9a5SSteve French 	cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
546238c8a9a5SSteve French 	rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
546338c8a9a5SSteve French 
546438c8a9a5SSteve French 	if (rc)
546538c8a9a5SSteve French 		return rc;
546638c8a9a5SSteve French 
546738c8a9a5SSteve French 	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
546838c8a9a5SSteve French 	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
546938c8a9a5SSteve French 
547038c8a9a5SSteve French 	params = 6;
547138c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
547238c8a9a5SSteve French 	pSMB->Reserved = 0;
547338c8a9a5SSteve French 	pSMB->Flags = 0;
547438c8a9a5SSteve French 	pSMB->Timeout = 0;
547538c8a9a5SSteve French 	pSMB->Reserved2 = 0;
547638c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
547738c8a9a5SSteve French 	offset = param_offset + params;
547838c8a9a5SSteve French 
547938c8a9a5SSteve French 	data_offset = (char *)pSMB +
548038c8a9a5SSteve French 			offsetof(struct smb_hdr, Protocol) + offset;
548138c8a9a5SSteve French 
548238c8a9a5SSteve French 	count = sizeof(FILE_UNIX_BASIC_INFO);
548338c8a9a5SSteve French 
548438c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
548538c8a9a5SSteve French 	/* BB find max SMB PDU from sess */
548638c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
548738c8a9a5SSteve French 	pSMB->SetupCount = 1;
548838c8a9a5SSteve French 	pSMB->Reserved3 = 0;
548938c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
549038c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
549138c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
549238c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
549338c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
549438c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
549538c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
549638c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
549738c8a9a5SSteve French 	pSMB->Fid = fid;
549838c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
549938c8a9a5SSteve French 	pSMB->Reserved4 = 0;
550038c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
550138c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
550238c8a9a5SSteve French 
550338c8a9a5SSteve French 	cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
550438c8a9a5SSteve French 
550538c8a9a5SSteve French 	rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
550638c8a9a5SSteve French 	cifs_small_buf_release(pSMB);
550738c8a9a5SSteve French 	if (rc)
550838c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
550938c8a9a5SSteve French 			 rc);
551038c8a9a5SSteve French 
551138c8a9a5SSteve French 	/* Note: On -EAGAIN error only caller can retry on handle based calls
551238c8a9a5SSteve French 		since file handle passed in no longer valid */
551338c8a9a5SSteve French 
551438c8a9a5SSteve French 	return rc;
551538c8a9a5SSteve French }
551638c8a9a5SSteve French 
551738c8a9a5SSteve French int
CIFSSMBUnixSetPathInfo(const unsigned int xid,struct cifs_tcon * tcon,const char * file_name,const struct cifs_unix_set_info_args * args,const struct nls_table * nls_codepage,int remap)551838c8a9a5SSteve French CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
551938c8a9a5SSteve French 		       const char *file_name,
552038c8a9a5SSteve French 		       const struct cifs_unix_set_info_args *args,
552138c8a9a5SSteve French 		       const struct nls_table *nls_codepage, int remap)
552238c8a9a5SSteve French {
552338c8a9a5SSteve French 	TRANSACTION2_SPI_REQ *pSMB = NULL;
552438c8a9a5SSteve French 	TRANSACTION2_SPI_RSP *pSMBr = NULL;
552538c8a9a5SSteve French 	int name_len;
552638c8a9a5SSteve French 	int rc = 0;
552738c8a9a5SSteve French 	int bytes_returned = 0;
552838c8a9a5SSteve French 	FILE_UNIX_BASIC_INFO *data_offset;
552938c8a9a5SSteve French 	__u16 params, param_offset, offset, count, byte_count;
553038c8a9a5SSteve French 
553138c8a9a5SSteve French 	cifs_dbg(FYI, "In SetUID/GID/Mode\n");
553238c8a9a5SSteve French setPermsRetry:
553338c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
553438c8a9a5SSteve French 		      (void **) &pSMBr);
553538c8a9a5SSteve French 	if (rc)
553638c8a9a5SSteve French 		return rc;
553738c8a9a5SSteve French 
553838c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
553938c8a9a5SSteve French 		name_len =
554038c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
554138c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
554238c8a9a5SSteve French 		name_len++;	/* trailing null */
554338c8a9a5SSteve French 		name_len *= 2;
554438c8a9a5SSteve French 	} else {
554538c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, file_name);
554638c8a9a5SSteve French 	}
554738c8a9a5SSteve French 
554838c8a9a5SSteve French 	params = 6 + name_len;
554938c8a9a5SSteve French 	count = sizeof(FILE_UNIX_BASIC_INFO);
555038c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
555138c8a9a5SSteve French 	/* BB find max SMB PDU from sess structure BB */
555238c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
555338c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
555438c8a9a5SSteve French 	pSMB->Reserved = 0;
555538c8a9a5SSteve French 	pSMB->Flags = 0;
555638c8a9a5SSteve French 	pSMB->Timeout = 0;
555738c8a9a5SSteve French 	pSMB->Reserved2 = 0;
555838c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
555938c8a9a5SSteve French 				InformationLevel) - 4;
556038c8a9a5SSteve French 	offset = param_offset + params;
556138c8a9a5SSteve French 	/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
556238c8a9a5SSteve French 	data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
556338c8a9a5SSteve French 	memset(data_offset, 0, count);
556438c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
556538c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
556638c8a9a5SSteve French 	pSMB->SetupCount = 1;
556738c8a9a5SSteve French 	pSMB->Reserved3 = 0;
556838c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
556938c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
557038c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
557138c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
557238c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
557338c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
557438c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
557538c8a9a5SSteve French 	pSMB->Reserved4 = 0;
557638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
557738c8a9a5SSteve French 
557838c8a9a5SSteve French 	cifs_fill_unix_set_info(data_offset, args);
557938c8a9a5SSteve French 
558038c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
558138c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
558238c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
558338c8a9a5SSteve French 	if (rc)
558438c8a9a5SSteve French 		cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
558538c8a9a5SSteve French 
558638c8a9a5SSteve French 	cifs_buf_release(pSMB);
558738c8a9a5SSteve French 	if (rc == -EAGAIN)
558838c8a9a5SSteve French 		goto setPermsRetry;
558938c8a9a5SSteve French 	return rc;
559038c8a9a5SSteve French }
559138c8a9a5SSteve French 
559238c8a9a5SSteve French #ifdef CONFIG_CIFS_XATTR
559338c8a9a5SSteve French /*
559438c8a9a5SSteve French  * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
559538c8a9a5SSteve French  * function used by listxattr and getxattr type calls. When ea_name is set,
559638c8a9a5SSteve French  * it looks for that attribute name and stuffs that value into the EAData
559738c8a9a5SSteve French  * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
559838c8a9a5SSteve French  * buffer. In both cases, the return value is either the length of the
559938c8a9a5SSteve French  * resulting data or a negative error code. If EAData is a NULL pointer then
560038c8a9a5SSteve French  * the data isn't copied to it, but the length is returned.
560138c8a9a5SSteve French  */
560238c8a9a5SSteve French ssize_t
CIFSSMBQAllEAs(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,const unsigned char * ea_name,char * EAData,size_t buf_size,struct cifs_sb_info * cifs_sb)560338c8a9a5SSteve French CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
560438c8a9a5SSteve French 		const unsigned char *searchName, const unsigned char *ea_name,
560538c8a9a5SSteve French 		char *EAData, size_t buf_size,
560638c8a9a5SSteve French 		struct cifs_sb_info *cifs_sb)
560738c8a9a5SSteve French {
560838c8a9a5SSteve French 		/* BB assumes one setup word */
560938c8a9a5SSteve French 	TRANSACTION2_QPI_REQ *pSMB = NULL;
561038c8a9a5SSteve French 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
561138c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
561238c8a9a5SSteve French 	struct nls_table *nls_codepage = cifs_sb->local_nls;
561338c8a9a5SSteve French 	int rc = 0;
561438c8a9a5SSteve French 	int bytes_returned;
561538c8a9a5SSteve French 	int list_len;
561638c8a9a5SSteve French 	struct fealist *ea_response_data;
561738c8a9a5SSteve French 	struct fea *temp_fea;
561838c8a9a5SSteve French 	char *temp_ptr;
561938c8a9a5SSteve French 	char *end_of_smb;
562038c8a9a5SSteve French 	__u16 params, byte_count, data_offset;
562138c8a9a5SSteve French 	unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
562238c8a9a5SSteve French 
562338c8a9a5SSteve French 	cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
562438c8a9a5SSteve French QAllEAsRetry:
562538c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
562638c8a9a5SSteve French 		      (void **) &pSMBr);
562738c8a9a5SSteve French 	if (rc)
562838c8a9a5SSteve French 		return rc;
562938c8a9a5SSteve French 
563038c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
563138c8a9a5SSteve French 		list_len =
563238c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
563338c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
563438c8a9a5SSteve French 		list_len++;	/* trailing null */
563538c8a9a5SSteve French 		list_len *= 2;
563638c8a9a5SSteve French 	} else {
563738c8a9a5SSteve French 		list_len = copy_path_name(pSMB->FileName, searchName);
563838c8a9a5SSteve French 	}
563938c8a9a5SSteve French 
564038c8a9a5SSteve French 	params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
564138c8a9a5SSteve French 	pSMB->TotalDataCount = 0;
564238c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
564338c8a9a5SSteve French 	/* BB find exact max SMB PDU from sess structure BB */
564438c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
564538c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
564638c8a9a5SSteve French 	pSMB->Reserved = 0;
564738c8a9a5SSteve French 	pSMB->Flags = 0;
564838c8a9a5SSteve French 	pSMB->Timeout = 0;
564938c8a9a5SSteve French 	pSMB->Reserved2 = 0;
565038c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(offsetof(
565138c8a9a5SSteve French 	struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
565238c8a9a5SSteve French 	pSMB->DataCount = 0;
565338c8a9a5SSteve French 	pSMB->DataOffset = 0;
565438c8a9a5SSteve French 	pSMB->SetupCount = 1;
565538c8a9a5SSteve French 	pSMB->Reserved3 = 0;
565638c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
565738c8a9a5SSteve French 	byte_count = params + 1 /* pad */ ;
565838c8a9a5SSteve French 	pSMB->TotalParameterCount = cpu_to_le16(params);
565938c8a9a5SSteve French 	pSMB->ParameterCount = pSMB->TotalParameterCount;
566038c8a9a5SSteve French 	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
566138c8a9a5SSteve French 	pSMB->Reserved4 = 0;
566238c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
566338c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
566438c8a9a5SSteve French 
566538c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
566638c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
566738c8a9a5SSteve French 	if (rc) {
566838c8a9a5SSteve French 		cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
566938c8a9a5SSteve French 		goto QAllEAsOut;
567038c8a9a5SSteve French 	}
567138c8a9a5SSteve French 
567238c8a9a5SSteve French 
567338c8a9a5SSteve French 	/* BB also check enough total bytes returned */
567438c8a9a5SSteve French 	/* BB we need to improve the validity checking
567538c8a9a5SSteve French 	of these trans2 responses */
567638c8a9a5SSteve French 
567738c8a9a5SSteve French 	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
567838c8a9a5SSteve French 	if (rc || get_bcc(&pSMBr->hdr) < 4) {
567938c8a9a5SSteve French 		rc = -EIO;	/* bad smb */
568038c8a9a5SSteve French 		goto QAllEAsOut;
568138c8a9a5SSteve French 	}
568238c8a9a5SSteve French 
568338c8a9a5SSteve French 	/* check that length of list is not more than bcc */
568438c8a9a5SSteve French 	/* check that each entry does not go beyond length
568538c8a9a5SSteve French 	   of list */
568638c8a9a5SSteve French 	/* check that each element of each entry does not
568738c8a9a5SSteve French 	   go beyond end of list */
568838c8a9a5SSteve French 	/* validate_trans2_offsets() */
568938c8a9a5SSteve French 	/* BB check if start of smb + data_offset > &bcc+ bcc */
569038c8a9a5SSteve French 
569138c8a9a5SSteve French 	data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
569238c8a9a5SSteve French 	ea_response_data = (struct fealist *)
569338c8a9a5SSteve French 				(((char *) &pSMBr->hdr.Protocol) + data_offset);
569438c8a9a5SSteve French 
569538c8a9a5SSteve French 	list_len = le32_to_cpu(ea_response_data->list_len);
569638c8a9a5SSteve French 	cifs_dbg(FYI, "ea length %d\n", list_len);
569738c8a9a5SSteve French 	if (list_len <= 8) {
569838c8a9a5SSteve French 		cifs_dbg(FYI, "empty EA list returned from server\n");
569938c8a9a5SSteve French 		/* didn't find the named attribute */
570038c8a9a5SSteve French 		if (ea_name)
570138c8a9a5SSteve French 			rc = -ENODATA;
570238c8a9a5SSteve French 		goto QAllEAsOut;
570338c8a9a5SSteve French 	}
570438c8a9a5SSteve French 
570538c8a9a5SSteve French 	/* make sure list_len doesn't go past end of SMB */
570638c8a9a5SSteve French 	end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
570738c8a9a5SSteve French 	if ((char *)ea_response_data + list_len > end_of_smb) {
570838c8a9a5SSteve French 		cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
570938c8a9a5SSteve French 		rc = -EIO;
571038c8a9a5SSteve French 		goto QAllEAsOut;
571138c8a9a5SSteve French 	}
571238c8a9a5SSteve French 
571338c8a9a5SSteve French 	/* account for ea list len */
571438c8a9a5SSteve French 	list_len -= 4;
571538c8a9a5SSteve French 	temp_fea = &ea_response_data->list;
571638c8a9a5SSteve French 	temp_ptr = (char *)temp_fea;
571738c8a9a5SSteve French 	while (list_len > 0) {
571838c8a9a5SSteve French 		unsigned int name_len;
571938c8a9a5SSteve French 		__u16 value_len;
572038c8a9a5SSteve French 
572138c8a9a5SSteve French 		list_len -= 4;
572238c8a9a5SSteve French 		temp_ptr += 4;
572338c8a9a5SSteve French 		/* make sure we can read name_len and value_len */
572438c8a9a5SSteve French 		if (list_len < 0) {
572538c8a9a5SSteve French 			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
572638c8a9a5SSteve French 			rc = -EIO;
572738c8a9a5SSteve French 			goto QAllEAsOut;
572838c8a9a5SSteve French 		}
572938c8a9a5SSteve French 
573038c8a9a5SSteve French 		name_len = temp_fea->name_len;
573138c8a9a5SSteve French 		value_len = le16_to_cpu(temp_fea->value_len);
573238c8a9a5SSteve French 		list_len -= name_len + 1 + value_len;
573338c8a9a5SSteve French 		if (list_len < 0) {
573438c8a9a5SSteve French 			cifs_dbg(FYI, "EA entry goes beyond length of list\n");
573538c8a9a5SSteve French 			rc = -EIO;
573638c8a9a5SSteve French 			goto QAllEAsOut;
573738c8a9a5SSteve French 		}
573838c8a9a5SSteve French 
573938c8a9a5SSteve French 		if (ea_name) {
574038c8a9a5SSteve French 			if (ea_name_len == name_len &&
574138c8a9a5SSteve French 			    memcmp(ea_name, temp_ptr, name_len) == 0) {
574238c8a9a5SSteve French 				temp_ptr += name_len + 1;
574338c8a9a5SSteve French 				rc = value_len;
574438c8a9a5SSteve French 				if (buf_size == 0)
574538c8a9a5SSteve French 					goto QAllEAsOut;
574638c8a9a5SSteve French 				if ((size_t)value_len > buf_size) {
574738c8a9a5SSteve French 					rc = -ERANGE;
574838c8a9a5SSteve French 					goto QAllEAsOut;
574938c8a9a5SSteve French 				}
575038c8a9a5SSteve French 				memcpy(EAData, temp_ptr, value_len);
575138c8a9a5SSteve French 				goto QAllEAsOut;
575238c8a9a5SSteve French 			}
575338c8a9a5SSteve French 		} else {
575438c8a9a5SSteve French 			/* account for prefix user. and trailing null */
575538c8a9a5SSteve French 			rc += (5 + 1 + name_len);
575638c8a9a5SSteve French 			if (rc < (int) buf_size) {
575738c8a9a5SSteve French 				memcpy(EAData, "user.", 5);
575838c8a9a5SSteve French 				EAData += 5;
575938c8a9a5SSteve French 				memcpy(EAData, temp_ptr, name_len);
576038c8a9a5SSteve French 				EAData += name_len;
576138c8a9a5SSteve French 				/* null terminate name */
576238c8a9a5SSteve French 				*EAData = 0;
576338c8a9a5SSteve French 				++EAData;
576438c8a9a5SSteve French 			} else if (buf_size == 0) {
576538c8a9a5SSteve French 				/* skip copy - calc size only */
576638c8a9a5SSteve French 			} else {
576738c8a9a5SSteve French 				/* stop before overrun buffer */
576838c8a9a5SSteve French 				rc = -ERANGE;
576938c8a9a5SSteve French 				break;
577038c8a9a5SSteve French 			}
577138c8a9a5SSteve French 		}
577238c8a9a5SSteve French 		temp_ptr += name_len + 1 + value_len;
577338c8a9a5SSteve French 		temp_fea = (struct fea *)temp_ptr;
577438c8a9a5SSteve French 	}
577538c8a9a5SSteve French 
577638c8a9a5SSteve French 	/* didn't find the named attribute */
577738c8a9a5SSteve French 	if (ea_name)
577838c8a9a5SSteve French 		rc = -ENODATA;
577938c8a9a5SSteve French 
578038c8a9a5SSteve French QAllEAsOut:
578138c8a9a5SSteve French 	cifs_buf_release(pSMB);
578238c8a9a5SSteve French 	if (rc == -EAGAIN)
578338c8a9a5SSteve French 		goto QAllEAsRetry;
578438c8a9a5SSteve French 
578538c8a9a5SSteve French 	return (ssize_t)rc;
578638c8a9a5SSteve French }
578738c8a9a5SSteve French 
578838c8a9a5SSteve French int
CIFSSMBSetEA(const unsigned int xid,struct cifs_tcon * tcon,const char * fileName,const char * ea_name,const void * ea_value,const __u16 ea_value_len,const struct nls_table * nls_codepage,struct cifs_sb_info * cifs_sb)578938c8a9a5SSteve French CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
579038c8a9a5SSteve French 	     const char *fileName, const char *ea_name, const void *ea_value,
579138c8a9a5SSteve French 	     const __u16 ea_value_len, const struct nls_table *nls_codepage,
579238c8a9a5SSteve French 	     struct cifs_sb_info *cifs_sb)
579338c8a9a5SSteve French {
579438c8a9a5SSteve French 	struct smb_com_transaction2_spi_req *pSMB = NULL;
579538c8a9a5SSteve French 	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
579638c8a9a5SSteve French 	struct fealist *parm_data;
579738c8a9a5SSteve French 	int name_len;
579838c8a9a5SSteve French 	int rc = 0;
579938c8a9a5SSteve French 	int bytes_returned = 0;
580038c8a9a5SSteve French 	__u16 params, param_offset, byte_count, offset, count;
580138c8a9a5SSteve French 	int remap = cifs_remap(cifs_sb);
580238c8a9a5SSteve French 
580338c8a9a5SSteve French 	cifs_dbg(FYI, "In SetEA\n");
580438c8a9a5SSteve French SetEARetry:
580538c8a9a5SSteve French 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
580638c8a9a5SSteve French 		      (void **) &pSMBr);
580738c8a9a5SSteve French 	if (rc)
580838c8a9a5SSteve French 		return rc;
580938c8a9a5SSteve French 
581038c8a9a5SSteve French 	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
581138c8a9a5SSteve French 		name_len =
581238c8a9a5SSteve French 		    cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
581338c8a9a5SSteve French 				       PATH_MAX, nls_codepage, remap);
581438c8a9a5SSteve French 		name_len++;	/* trailing null */
581538c8a9a5SSteve French 		name_len *= 2;
581638c8a9a5SSteve French 	} else {
581738c8a9a5SSteve French 		name_len = copy_path_name(pSMB->FileName, fileName);
581838c8a9a5SSteve French 	}
581938c8a9a5SSteve French 
582038c8a9a5SSteve French 	params = 6 + name_len;
582138c8a9a5SSteve French 
582238c8a9a5SSteve French 	/* done calculating parms using name_len of file name,
582338c8a9a5SSteve French 	now use name_len to calculate length of ea name
582438c8a9a5SSteve French 	we are going to create in the inode xattrs */
582538c8a9a5SSteve French 	if (ea_name == NULL)
582638c8a9a5SSteve French 		name_len = 0;
582738c8a9a5SSteve French 	else
582838c8a9a5SSteve French 		name_len = strnlen(ea_name, 255);
582938c8a9a5SSteve French 
583038c8a9a5SSteve French 	count = sizeof(*parm_data) + 1 + ea_value_len + name_len;
583138c8a9a5SSteve French 	pSMB->MaxParameterCount = cpu_to_le16(2);
583238c8a9a5SSteve French 	/* BB find max SMB PDU from sess */
583338c8a9a5SSteve French 	pSMB->MaxDataCount = cpu_to_le16(1000);
583438c8a9a5SSteve French 	pSMB->MaxSetupCount = 0;
583538c8a9a5SSteve French 	pSMB->Reserved = 0;
583638c8a9a5SSteve French 	pSMB->Flags = 0;
583738c8a9a5SSteve French 	pSMB->Timeout = 0;
583838c8a9a5SSteve French 	pSMB->Reserved2 = 0;
583938c8a9a5SSteve French 	param_offset = offsetof(struct smb_com_transaction2_spi_req,
584038c8a9a5SSteve French 				InformationLevel) - 4;
584138c8a9a5SSteve French 	offset = param_offset + params;
584238c8a9a5SSteve French 	pSMB->InformationLevel =
584338c8a9a5SSteve French 		cpu_to_le16(SMB_SET_FILE_EA);
584438c8a9a5SSteve French 
584538c8a9a5SSteve French 	parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
584638c8a9a5SSteve French 	pSMB->ParameterOffset = cpu_to_le16(param_offset);
584738c8a9a5SSteve French 	pSMB->DataOffset = cpu_to_le16(offset);
584838c8a9a5SSteve French 	pSMB->SetupCount = 1;
584938c8a9a5SSteve French 	pSMB->Reserved3 = 0;
585038c8a9a5SSteve French 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
585138c8a9a5SSteve French 	byte_count = 3 /* pad */  + params + count;
585238c8a9a5SSteve French 	pSMB->DataCount = cpu_to_le16(count);
585338c8a9a5SSteve French 	parm_data->list_len = cpu_to_le32(count);
585438c8a9a5SSteve French 	parm_data->list.EA_flags = 0;
585538c8a9a5SSteve French 	/* we checked above that name len is less than 255 */
585638c8a9a5SSteve French 	parm_data->list.name_len = (__u8)name_len;
585738c8a9a5SSteve French 	/* EA names are always ASCII */
585838c8a9a5SSteve French 	if (ea_name)
585938c8a9a5SSteve French 		strncpy(parm_data->list.name, ea_name, name_len);
586038c8a9a5SSteve French 	parm_data->list.name[name_len] = '\0';
586138c8a9a5SSteve French 	parm_data->list.value_len = cpu_to_le16(ea_value_len);
586238c8a9a5SSteve French 	/* caller ensures that ea_value_len is less than 64K but
586338c8a9a5SSteve French 	we need to ensure that it fits within the smb */
586438c8a9a5SSteve French 
586538c8a9a5SSteve French 	/*BB add length check to see if it would fit in
586638c8a9a5SSteve French 	     negotiated SMB buffer size BB */
586738c8a9a5SSteve French 	/* if (ea_value_len > buffer_size - 512 (enough for header)) */
586838c8a9a5SSteve French 	if (ea_value_len)
586938c8a9a5SSteve French 		memcpy(parm_data->list.name + name_len + 1,
587038c8a9a5SSteve French 		       ea_value, ea_value_len);
587138c8a9a5SSteve French 
587238c8a9a5SSteve French 	pSMB->TotalDataCount = pSMB->DataCount;
587338c8a9a5SSteve French 	pSMB->ParameterCount = cpu_to_le16(params);
587438c8a9a5SSteve French 	pSMB->TotalParameterCount = pSMB->ParameterCount;
587538c8a9a5SSteve French 	pSMB->Reserved4 = 0;
587638c8a9a5SSteve French 	inc_rfc1001_len(pSMB, byte_count);
587738c8a9a5SSteve French 	pSMB->ByteCount = cpu_to_le16(byte_count);
587838c8a9a5SSteve French 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
587938c8a9a5SSteve French 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
588038c8a9a5SSteve French 	if (rc)
588138c8a9a5SSteve French 		cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
588238c8a9a5SSteve French 
588338c8a9a5SSteve French 	cifs_buf_release(pSMB);
588438c8a9a5SSteve French 
588538c8a9a5SSteve French 	if (rc == -EAGAIN)
588638c8a9a5SSteve French 		goto SetEARetry;
588738c8a9a5SSteve French 
588838c8a9a5SSteve French 	return rc;
588938c8a9a5SSteve French }
589038c8a9a5SSteve French #endif
5891