Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
new file mode 100644
index 0000000..df6a619
--- /dev/null
+++ b/fs/cifs/cifssmb.c
@@ -0,0 +1,4186 @@
+/*
+ *   fs/cifs/cifssmb.c
+ *
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   Contains the routines for constructing the SMB PDUs themselves
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
+ /* These are mostly routines that operate on a pathname, or on a tree id     */
+ /* (mounted volume), but there are eight handle based routines which must be */
+ /* treated slightly different for reconnection purposes since we never want  */
+ /* to reuse a stale file handle and the caller knows the file handle */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/vfs.h>
+#include <linux/posix_acl_xattr.h>
+#include <asm/uaccess.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+
+#ifdef CONFIG_CIFS_POSIX
+static struct {
+	int index;
+	char *name;
+} protocols[] = {
+	{CIFS_PROT, "\2NT LM 0.12"}, 
+	{CIFS_PROT, "\2POSIX 2"},
+	{BAD_PROT, "\2"}
+};
+#else
+static struct {
+	int index;
+	char *name;
+} protocols[] = {
+	{CIFS_PROT, "\2NT LM 0.12"}, 
+	{BAD_PROT, "\2"}
+};
+#endif
+
+
+/* Mark as invalid, all open files on tree connections since they
+   were closed when session to server was lost */
+static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
+{
+	struct cifsFileInfo *open_file = NULL;
+	struct list_head * tmp;
+	struct list_head * tmp1;
+
+/* list all files open on tree connection and mark them invalid */
+	write_lock(&GlobalSMBSeslock);
+	list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
+		open_file = list_entry(tmp,struct cifsFileInfo, tlist);
+		if(open_file) {
+			open_file->invalidHandle = TRUE;
+		}
+	}
+	write_unlock(&GlobalSMBSeslock);
+	/* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
+}
+
+/* If the return code is zero, this function must fill in request_buf pointer */
+static int
+small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+	 void **request_buf /* returned */)
+{
+	int rc = 0;
+
+	/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
+	   check for tcp and smb session status done differently
+	   for those three - in the calling routine */
+	if(tcon) {
+		if((tcon->ses) && (tcon->ses->server)){
+			struct nls_table *nls_codepage;
+				/* Give Demultiplex thread up to 10 seconds to 
+					reconnect, should be greater than cifs socket
+					timeout which is 7 seconds */
+			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+				wait_event_interruptible_timeout(tcon->ses->server->response_q,
+					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
+				if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+					/* on "soft" mounts we wait once */
+					if((tcon->retry == FALSE) || 
+					   (tcon->ses->status == CifsExiting)) {
+						cFYI(1,("gave up waiting on reconnect in smb_init"));
+						return -EHOSTDOWN;
+					} /* else "hard" mount - keep retrying until 
+					process is killed or server comes back up */
+				} else /* TCP session is reestablished now */
+					break;
+				 
+			}
+			
+			nls_codepage = load_nls_default();
+		/* need to prevent multiple threads trying to
+		simultaneously reconnect the same SMB session */
+			down(&tcon->ses->sesSem);
+			if(tcon->ses->status == CifsNeedReconnect)
+				rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+			if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+				mark_open_files_invalid(tcon);
+				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
+					nls_codepage);
+				up(&tcon->ses->sesSem);
+				if(rc == 0)
+					atomic_inc(&tconInfoReconnectCount);
+
+				cFYI(1, ("reconnect tcon rc = %d", rc));
+				/* Removed call to reopen open files here - 
+					it is safer (and faster) to reopen files
+					one at a time as needed in read and write */
+
+				/* Check if handle based operation so we 
+					know whether we can continue or not without
+					returning to caller to reset file handle */
+				switch(smb_command) {
+					case SMB_COM_READ_ANDX:
+					case SMB_COM_WRITE_ANDX:
+					case SMB_COM_CLOSE:
+					case SMB_COM_FIND_CLOSE2:
+					case SMB_COM_LOCKING_ANDX: {
+						unload_nls(nls_codepage);
+						return -EAGAIN;
+					}
+				}
+			} else {
+				up(&tcon->ses->sesSem);
+			}
+			unload_nls(nls_codepage);
+
+		} else {
+			return -EIO;
+		}
+	}
+	if(rc)
+		return rc;
+
+	*request_buf = cifs_small_buf_get();
+	if (*request_buf == NULL) {
+		/* BB should we add a retry in here if not a writepage? */
+		return -ENOMEM;
+	}
+
+	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
+
+#ifdef CONFIG_CIFS_STATS
+        if(tcon != NULL) {
+                atomic_inc(&tcon->num_smbs_sent);
+        }
+#endif /* CONFIG_CIFS_STATS */
+	return rc;
+}  
+
+/* If the return code is zero, this function must fill in request_buf pointer */
+static int
+smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+	 void **request_buf /* returned */ ,
+	 void **response_buf /* returned */ )
+{
+	int rc = 0;
+
+	/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
+	   check for tcp and smb session status done differently
+	   for those three - in the calling routine */
+	if(tcon) {
+		if((tcon->ses) && (tcon->ses->server)){
+			struct nls_table *nls_codepage;
+				/* Give Demultiplex thread up to 10 seconds to 
+					reconnect, should be greater than cifs socket
+					timeout which is 7 seconds */
+			while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+				wait_event_interruptible_timeout(tcon->ses->server->response_q,
+					(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
+				if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+					/* on "soft" mounts we wait once */
+					if((tcon->retry == FALSE) || 
+					   (tcon->ses->status == CifsExiting)) {
+						cFYI(1,("gave up waiting on reconnect in smb_init"));
+						return -EHOSTDOWN;
+					} /* else "hard" mount - keep retrying until 
+					process is killed or server comes back up */
+				} else /* TCP session is reestablished now */
+					break;
+				 
+			}
+			
+			nls_codepage = load_nls_default();
+		/* need to prevent multiple threads trying to
+		simultaneously reconnect the same SMB session */
+			down(&tcon->ses->sesSem);
+			if(tcon->ses->status == CifsNeedReconnect)
+				rc = cifs_setup_session(0, tcon->ses, nls_codepage);
+			if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+				mark_open_files_invalid(tcon);
+				rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
+					nls_codepage);
+				up(&tcon->ses->sesSem);
+				if(rc == 0)
+					atomic_inc(&tconInfoReconnectCount);
+
+				cFYI(1, ("reconnect tcon rc = %d", rc));
+				/* Removed call to reopen open files here - 
+					it is safer (and faster) to reopen files
+					one at a time as needed in read and write */
+
+				/* Check if handle based operation so we 
+					know whether we can continue or not without
+					returning to caller to reset file handle */
+				switch(smb_command) {
+					case SMB_COM_READ_ANDX:
+					case SMB_COM_WRITE_ANDX:
+					case SMB_COM_CLOSE:
+					case SMB_COM_FIND_CLOSE2:
+					case SMB_COM_LOCKING_ANDX: {
+						unload_nls(nls_codepage);
+						return -EAGAIN;
+					}
+				}
+			} else {
+				up(&tcon->ses->sesSem);
+			}
+			unload_nls(nls_codepage);
+
+		} else {
+			return -EIO;
+		}
+	}
+	if(rc)
+		return rc;
+
+	*request_buf = cifs_buf_get();
+	if (*request_buf == NULL) {
+		/* BB should we add a retry in here if not a writepage? */
+		return -ENOMEM;
+	}
+    /* Although the original thought was we needed the response buf for  */
+    /* potential retries of smb operations it turns out we can determine */
+    /* from the mid flags when the request buffer can be resent without  */
+    /* having to use a second distinct buffer for the response */
+	*response_buf = *request_buf; 
+
+	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
+			wct /*wct */ );
+
+#ifdef CONFIG_CIFS_STATS
+        if(tcon != NULL) {
+                atomic_inc(&tcon->num_smbs_sent);
+        }
+#endif /* CONFIG_CIFS_STATS */
+	return rc;
+}
+
+static int validate_t2(struct smb_t2_rsp * pSMB) 
+{
+	int rc = -EINVAL;
+	int total_size;
+	char * pBCC;
+
+	/* check for plausible wct, bcc and t2 data and parm sizes */
+	/* check for parm and data offset going beyond end of smb */
+	if(pSMB->hdr.WordCount >= 10) {
+		if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
+		   (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
+			/* check that bcc is at least as big as parms + data */
+			/* check that bcc is less than negotiated smb buffer */
+			total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
+			if(total_size < 512) {
+				total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
+				/* BCC le converted in SendReceive */
+				pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + 
+					(char *)pSMB;
+				if((total_size <= (*(u16 *)pBCC)) && 
+				   (total_size < 
+					CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
+					return 0;
+				}
+				
+			}
+		}
+	}
+	cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
+		sizeof(struct smb_t2_rsp) + 16);
+	return rc;
+}
+int
+CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
+{
+	NEGOTIATE_REQ *pSMB;
+	NEGOTIATE_RSP *pSMBr;
+	int rc = 0;
+	int bytes_returned;
+	struct TCP_Server_Info * server;
+	u16 count;
+
+	if(ses->server)
+		server = ses->server;
+	else {
+		rc = -EIO;
+		return rc;
+	}
+	rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
+		      (void **) &pSMB, (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
+	if (extended_security)
+		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+
+	count = strlen(protocols[0].name) + 1;
+	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	
+    /* null guaranteed to be at end of source and target buffers anyway */
+
+	pSMB->hdr.smb_buf_length += count;
+	pSMB->ByteCount = cpu_to_le16(count);
+
+	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc == 0) {
+		server->secMode = pSMBr->SecurityMode;	
+		server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
+		/* one byte - no need to convert this or EncryptionKeyLen from le,*/
+		server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+		/* probably no need to store and check maxvcs */
+		server->maxBuf =
+			min(le32_to_cpu(pSMBr->MaxBufferSize),
+			(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+		server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
+		cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
+		GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
+		server->capabilities = le32_to_cpu(pSMBr->Capabilities);
+		server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);	
+        /* BB with UTC do we ever need to be using srvr timezone? */
+		if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+			memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
+			       CIFS_CRYPTO_KEY_SIZE);
+		} else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
+			   && (pSMBr->EncryptionKeyLength == 0)) {
+			/* decode security blob */
+		} else
+			rc = -EIO;
+
+		/* BB might be helpful to save off the domain of server here */
+
+		if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
+			(server->capabilities & CAP_EXTENDED_SECURITY)) {
+			count = pSMBr->ByteCount;
+			if (count < 16)
+				rc = -EIO;
+			else if (count == 16) {
+				server->secType = RawNTLMSSP;
+				if (server->socketUseCount.counter > 1) {
+					if (memcmp
+						(server->server_GUID,
+						pSMBr->u.extended_response.
+						GUID, 16) != 0) {
+						cFYI(1,
+							("UID of server does not match previous connection to same ip address"));
+						memcpy(server->
+							server_GUID,
+							pSMBr->u.
+							extended_response.
+							GUID, 16);
+					}
+				} else
+					memcpy(server->server_GUID,
+					       pSMBr->u.extended_response.
+					       GUID, 16);
+			} else {
+				rc = decode_negTokenInit(pSMBr->u.
+							 extended_response.
+							 SecurityBlob,
+							 count - 16,
+							 &server->secType);
+				if(rc == 1) {
+				/* BB Need to fill struct for sessetup here */
+					rc = -EOPNOTSUPP;
+				} else {
+					rc = -EINVAL;
+				}
+			}
+		} else
+			server->capabilities &= ~CAP_EXTENDED_SECURITY;
+		if(sign_CIFS_PDUs == FALSE) {        
+			if(server->secMode & SECMODE_SIGN_REQUIRED)
+				cERROR(1,
+				 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
+			server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+		} else if(sign_CIFS_PDUs == 1) {
+			if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
+				server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+		}
+				
+	}
+	if (pSMB)
+		cifs_buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
+{
+	struct smb_hdr *smb_buffer;
+	struct smb_hdr *smb_buffer_response; /* BB removeme BB */
+	int rc = 0;
+	int length;
+
+	cFYI(1, ("In tree disconnect"));
+	/*
+	 *  If last user of the connection and
+	 *  connection alive - disconnect it
+	 *  If this is the last connection on the server session disconnect it
+	 *  (and inside session disconnect we should check if tcp socket needs 
+	 *  to be freed and kernel thread woken up).
+	 */
+	if (tcon)
+		down(&tcon->tconSem);
+	else
+		return -EIO;
+
+	atomic_dec(&tcon->useCount);
+	if (atomic_read(&tcon->useCount) > 0) {
+		up(&tcon->tconSem);
+		return -EBUSY;
+	}
+
+	/* No need to return error on this operation if tid invalidated and 
+	closed on server already e.g. due to tcp session crashing */
+	if(tcon->tidStatus == CifsNeedReconnect) {
+		up(&tcon->tconSem);
+		return 0;  
+	}
+
+	if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {    
+		up(&tcon->tconSem);
+		return -EIO;
+	}
+	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer);
+	if (rc) {
+		up(&tcon->tconSem);
+		return rc;
+	} else {
+		smb_buffer_response = smb_buffer; /* BB removeme BB */
+    }
+	rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
+			 &length, 0);
+	if (rc)
+		cFYI(1, (" Tree disconnect failed %d", rc));
+
+	if (smb_buffer)
+		cifs_small_buf_release(smb_buffer);
+	up(&tcon->tconSem);
+
+	/* No need to return error on this operation if tid invalidated and 
+	closed on server already e.g. due to tcp session crashing */
+	if (rc == -EAGAIN)
+		rc = 0;
+
+	return rc;
+}
+
+int
+CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
+{
+	struct smb_hdr *smb_buffer_response;
+	LOGOFF_ANDX_REQ *pSMB;
+	int rc = 0;
+	int length;
+
+	cFYI(1, ("In SMBLogoff for session disconnect"));
+	if (ses)
+		down(&ses->sesSem);
+	else
+		return -EIO;
+
+	atomic_dec(&ses->inUse);
+	if (atomic_read(&ses->inUse) > 0) {
+		up(&ses->sesSem);
+		return -EBUSY;
+	}
+	rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
+	if (rc) {
+		up(&ses->sesSem);
+		return rc;
+	}
+
+	smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
+	
+	if(ses->server) {
+		if(ses->server->secMode & 
+		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+	}
+
+	pSMB->hdr.Uid = ses->Suid;
+
+	pSMB->AndXCommand = 0xFF;
+	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+			 smb_buffer_response, &length, 0);
+	if (ses->server) {
+		atomic_dec(&ses->server->socketUseCount);
+		if (atomic_read(&ses->server->socketUseCount) == 0) {
+			spin_lock(&GlobalMid_Lock);
+			ses->server->tcpStatus = CifsExiting;
+			spin_unlock(&GlobalMid_Lock);
+			rc = -ESHUTDOWN;
+		}
+	}
+	if (pSMB)
+		cifs_small_buf_release(pSMB);
+	up(&ses->sesSem);
+
+	/* if session dead then we do not need to do ulogoff,
+		since server closed smb session, no sense reporting 
+		error */
+	if (rc == -EAGAIN)
+		rc = 0;
+	return rc;
+}
+
+int
+CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
+	       const char *fileName, const struct nls_table *nls_codepage)
+{
+	DELETE_FILE_REQ *pSMB = NULL;
+	DELETE_FILE_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+DelFileRetry:
+	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += name_len + 1;
+	pSMB->ByteCount = cpu_to_le16(name_len + 1);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Error in RMFile = %d", rc));
+	} 
+#ifdef CONFIG_CIFS_STATS
+        else {
+		atomic_inc(&tcon->num_deletes);
+        }
+#endif
+
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto DelFileRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
+	     const char *dirName, const struct nls_table *nls_codepage)
+{
+	DELETE_DIRECTORY_REQ *pSMB = NULL;
+	DELETE_DIRECTORY_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("In CIFSSMBRmDir"));
+RmDirRetry:
+	rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX
+				/* find define for this maxpathcomponent */
+				, nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(dirName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->DirName, dirName, name_len);
+	}
+
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += name_len + 1;
+	pSMB->ByteCount = cpu_to_le16(name_len + 1);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Error in RMDir = %d", rc));
+	}
+#ifdef CONFIG_CIFS_STATS
+        else {
+		atomic_inc(&tcon->num_rmdirs);
+        }
+#endif
+
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto RmDirRetry;
+	return rc;
+}
+
+int
+CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
+	     const char *name, const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	CREATE_DIRECTORY_REQ *pSMB = NULL;
+	CREATE_DIRECTORY_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("In CIFSSMBMkDir"));
+MkDirRetry:
+	rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX
+					 /* find define for this maxpathcomponent */
+					 , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(name, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->DirName, name, name_len);
+	}
+
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += name_len + 1;
+	pSMB->ByteCount = cpu_to_le16(name_len + 1);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Error in Mkdir = %d", rc));
+	}
+#ifdef CONFIG_CIFS_STATS
+        else {
+		atomic_inc(&tcon->num_mkdirs);
+        }
+#endif
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto MkDirRetry;
+	return rc;
+}
+
+int
+CIFSSMBOpen(const int xid, struct cifsTconInfo *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 rc = -EACCES;
+	OPEN_REQ *pSMB = NULL;
+	OPEN_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len;
+	__u16 count;
+
+openRetry:
+	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->AndXCommand = 0xFF;	/* none */
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		count = 1;	/* account for one byte pad to word boundary */
+		name_len =
+		    cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
+				  fileName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+		pSMB->NameLength = cpu_to_le16(name_len);
+	} else {		/* BB improve the check for buffer overruns BB */
+		count = 0;	/* no pad */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		pSMB->NameLength = cpu_to_le16(name_len);
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	if (*pOplock & REQ_OPLOCK)
+		pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
+	else if (*pOplock & REQ_BATCHOPLOCK) {
+		pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
+	}
+	pSMB->DesiredAccess = cpu_to_le32(access_flags);
+	pSMB->AllocationSize = 0;
+	pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
+	/* XP does not handle ATTR_POSIX_SEMANTICS */
+	/* but it helps speed up case sensitive checks for other
+	servers such as Samba */
+	if (tcon->ses->capabilities & CAP_UNIX)
+		pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
+
+	/* if ((omode & S_IWUGO) == 0)
+		pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
+	/*  Above line causes problems due to vfs splitting create into two
+		pieces - need to set mode after file created not while it is
+		being created */
+	pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
+	pSMB->CreateDisposition = cpu_to_le32(openDisposition);
+	pSMB->CreateOptions = cpu_to_le32(create_options);
+	pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);	/* BB ??*/
+	pSMB->SecurityFlags =
+	    SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
+
+	count += name_len;
+	pSMB->hdr.smb_buf_length += count;
+
+	pSMB->ByteCount = cpu_to_le16(count);
+	/* long_op set to 1 to allow for oplock break timeouts */
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+	if (rc) {
+		cFYI(1, ("Error in Open = %d", rc));
+	} else {
+		*pOplock = pSMBr->OplockLevel;	/* one byte no need to le_to_cpu */
+		*netfid = pSMBr->Fid;	/* cifs fid stays in le */
+		/* Let caller know file was created so we can set the mode. */
+		/* Do we care about the CreateAction in any other cases? */
+		if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+			*pOplock |= CIFS_CREATE_ACTION; 
+		if(pfile_info) {
+		    memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
+			36 /* CreationTime to Attributes */);
+		    /* the file_info buf is endian converted by caller */
+		    pfile_info->AllocationSize = pSMBr->AllocationSize;
+		    pfile_info->EndOfFile = pSMBr->EndOfFile;
+		    pfile_info->NumberOfLinks = cpu_to_le32(1);
+		}
+
+#ifdef CONFIG_CIFS_STATS
+		atomic_inc(&tcon->num_opens);
+#endif
+	}
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto openRetry;
+	return rc;
+}
+
+/* If no buffer passed in, then caller wants to do the copy
+	as in the case of readpages so the SMB buffer must be
+	freed by the caller */
+
+int
+CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
+	    const int netfid, const unsigned int count,
+	    const __u64 lseek, unsigned int *nbytes, char **buf)
+{
+	int rc = -EACCES;
+	READ_REQ *pSMB = NULL;
+	READ_RSP *pSMBr = NULL;
+	char *pReadData = NULL;
+	int bytes_returned;
+
+	cFYI(1,("Reading %d bytes on fid %d",count,netfid));
+
+	*nbytes = 0;
+	rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	/* tcon and ses pointer are checked in smb_init */
+	if (tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	pSMB->AndXCommand = 0xFF;	/* none */
+	pSMB->Fid = netfid;
+	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
+	pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+	pSMB->Remaining = 0;
+	pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
+	pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
+	pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("Send error in read = %d", rc));
+	} else {
+		int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
+		data_length = data_length << 16;
+		data_length += le16_to_cpu(pSMBr->DataLength);
+		*nbytes = data_length;
+
+		/*check that DataLength would not go beyond end of SMB */
+		if ((data_length > CIFSMaxBufSize) 
+				|| (data_length > count)) {
+			cFYI(1,("bad length %d for count %d",data_length,count));
+			rc = -EIO;
+			*nbytes = 0;
+		} else {
+			pReadData =
+			    (char *) (&pSMBr->hdr.Protocol) +
+			    le16_to_cpu(pSMBr->DataOffset);
+/*			if(rc = copy_to_user(buf, pReadData, data_length)) {
+				cERROR(1,("Faulting on read rc = %d",rc));
+				rc = -EFAULT;
+			}*/ /* can not use copy_to_user when using page cache*/
+			if(*buf)
+			    memcpy(*buf,pReadData,data_length);
+		}
+	}
+	if(*buf)
+		cifs_buf_release(pSMB);
+	else
+		*buf = (char *)pSMB;
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls 
+		since file handle passed in no longer valid */
+	return rc;
+}
+
+int
+CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
+	     const int netfid, const unsigned int count,
+	     const __u64 offset, unsigned int *nbytes, const char *buf,
+	     const char __user * ubuf, const int long_op)
+{
+	int rc = -EACCES;
+	WRITE_REQ *pSMB = NULL;
+	WRITE_RSP *pSMBr = NULL;
+	int bytes_returned;
+	__u32 bytes_sent;
+	__u16 byte_count;
+
+	/* cFYI(1,("write at %lld %d bytes",offset,count));*/
+	rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+	/* tcon and ses pointer are checked in smb_init */
+	if (tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	pSMB->AndXCommand = 0xFF;	/* none */
+	pSMB->Fid = netfid;
+	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
+	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	pSMB->Reserved = 0xFFFFFFFF;
+	pSMB->WriteMode = 0;
+	pSMB->Remaining = 0;
+
+	/* Can increase buffer size if buffer is big enough in some cases - ie we 
+	can send more if LARGE_WRITE_X capability returned by the server and if
+	our buffer is big enough or if we convert to iovecs on socket writes
+	and eliminate the copy to the CIFS buffer */
+	if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+		bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
+	} else {
+		bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
+			 & ~0xFF;
+	}
+
+	if (bytes_sent > count)
+		bytes_sent = count;
+	pSMB->DataOffset =
+	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+	if(buf)
+	    memcpy(pSMB->Data,buf,bytes_sent);
+	else if(ubuf) {
+		if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
+			cifs_buf_release(pSMB);
+			return -EFAULT;
+		}
+	} else {
+		/* No buffer */
+		cifs_buf_release(pSMB);
+		return -EINVAL;
+	}
+
+	byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
+	pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
+	pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
+	pSMB->hdr.smb_buf_length += bytes_sent+1;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+	if (rc) {
+		cFYI(1, ("Send error in write = %d", rc));
+		*nbytes = 0;
+	} else {
+		*nbytes = le16_to_cpu(pSMBr->CountHigh);
+		*nbytes = (*nbytes) << 16;
+		*nbytes += le16_to_cpu(pSMBr->Count);
+	}
+
+	cifs_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls 
+		since file handle passed in no longer valid */
+
+	return rc;
+}
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
+	     const int netfid, const unsigned int count,
+	     const __u64 offset, unsigned int *nbytes, const char __user *buf,
+	     const int long_op)
+{
+	int rc = -EACCES;
+	WRITE_REQ *pSMB = NULL;
+	WRITE_RSP *pSMBr = NULL;
+	/*int bytes_returned;*/
+	unsigned bytes_sent;
+	__u16 byte_count;
+
+	rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
+    
+	if (rc)
+		return rc;
+	
+	pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
+
+	/* tcon and ses pointer are checked in smb_init */
+	if (tcon->ses->server == NULL)
+		return -ECONNABORTED;
+
+	pSMB->AndXCommand = 0xFF; /* none */
+	pSMB->Fid = netfid;
+	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
+	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	pSMB->Reserved = 0xFFFFFFFF;
+	pSMB->WriteMode = 0;
+	pSMB->Remaining = 0;
+	bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
+	if (bytes_sent > count)
+		bytes_sent = count;
+	pSMB->DataLengthHigh = 0;
+	pSMB->DataOffset =
+	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+
+	byte_count = bytes_sent + 1 /* pad */ ;
+	pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
+	pSMB->DataLengthHigh = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+/*	rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */  /* BB fixme BB */
+	if (rc) {
+		cFYI(1, ("Send error in write2 (large write) = %d", rc));
+		*nbytes = 0;
+	} else
+		*nbytes = le16_to_cpu(pSMBr->Count);
+
+	cifs_small_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls 
+		since file handle passed in no longer valid */
+
+	return rc;
+}
+#endif /* CIFS_EXPERIMENTAL */
+
+int
+CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
+	    const __u16 smb_file_id, const __u64 len,
+	    const __u64 offset, const __u32 numUnlock,
+	    const __u32 numLock, const __u8 lockType, const int waitFlag)
+{
+	int rc = 0;
+	LOCK_REQ *pSMB = NULL;
+	LOCK_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int timeout = 0;
+	__u16 count;
+
+	cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
+	rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
+		timeout = -1; /* no response expected */
+		pSMB->Timeout = 0;
+	} else if (waitFlag == TRUE) {
+		timeout = 3;  /* blocking operation, no timeout */
+		pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
+	} else {
+		pSMB->Timeout = 0;
+	}
+
+	pSMB->NumberOfLocks = cpu_to_le16(numLock);
+	pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
+	pSMB->LockType = lockType;
+	pSMB->AndXCommand = 0xFF;	/* none */
+	pSMB->Fid = smb_file_id; /* netfid stays le */
+
+	if((numLock != 0) || (numUnlock != 0)) {
+		pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
+		/* BB where to store pid high? */
+		pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
+		pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
+		pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
+		pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
+		count = sizeof(LOCKING_ANDX_RANGE);
+	} else {
+		/* oplock break */
+		count = 0;
+	}
+	pSMB->hdr.smb_buf_length += count;
+	pSMB->ByteCount = cpu_to_le16(count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
+
+	if (rc) {
+		cFYI(1, ("Send error in Lock = %d", rc));
+	}
+	cifs_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls 
+	since file handle passed in no longer valid */
+	return rc;
+}
+
+int
+CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
+{
+	int rc = 0;
+	CLOSE_REQ *pSMB = NULL;
+	CLOSE_RSP *pSMBr = NULL;
+	int bytes_returned;
+	cFYI(1, ("In CIFSSMBClose"));
+
+/* do not retry on dead session on close */
+	rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
+	if(rc == -EAGAIN)
+		return 0;
+	if (rc)
+		return rc;
+
+	pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
+
+	pSMB->FileID = (__u16) smb_file_id;
+	pSMB->LastWriteTime = 0;
+	pSMB->ByteCount = 0;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		if(rc!=-EINTR) {
+			/* EINTR is expected when user ctl-c to kill app */
+			cERROR(1, ("Send error in Close = %d", rc));
+		}
+	}
+
+	cifs_small_buf_release(pSMB);
+
+	/* Since session is dead, file will be closed on server already */
+	if(rc == -EAGAIN)
+		rc = 0;
+
+	return rc;
+}
+
+int
+CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
+	      const char *fromName, const char *toName,
+	      const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	RENAME_REQ *pSMB = NULL;
+	RENAME_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len, name_len2;
+	__u16 count;
+
+	cFYI(1, ("In CIFSSMBRename"));
+renameRetry:
+	rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->BufferFormat = 0x04;
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+		pSMB->OldFileName[name_len] = 0x04;	/* pad */
+	/* protocol requires ASCII signature byte on Unicode string */
+		pSMB->OldFileName[name_len + 1] = 0x00;
+		name_len2 =
+		    cifs_strtoUCS((wchar_t *) & pSMB->
+				  OldFileName[name_len + 2], toName, PATH_MAX,
+				  nls_codepage);
+		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
+		name_len2 *= 2;	/* convert to bytes */
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fromName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->OldFileName, fromName, name_len);
+		name_len2 = strnlen(toName, PATH_MAX);
+		name_len2++;	/* trailing null */
+		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
+		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		name_len2++;	/* trailing null */
+		name_len2++;	/* signature byte */
+	}
+
+	count = 1 /* 1st signature byte */  + name_len + name_len2;
+	pSMB->hdr.smb_buf_length += count;
+	pSMB->ByteCount = cpu_to_le16(count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in rename = %d", rc));
+	} 
+
+#ifdef CONFIG_CIFS_STATS
+	  else {
+		atomic_inc(&tcon->num_renames);
+	}
+#endif
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto renameRetry;
+
+	return rc;
+}
+
+int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
+		int netfid, char * target_name, const struct nls_table * nls_codepage) 
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	struct set_file_rename * rename_info;
+	char *data_offset;
+	char dummy_string[30];
+	int rc = 0;
+	int bytes_returned = 0;
+	int len_of_str;
+	__u16 params, param_offset, offset, count, byte_count;
+
+	cFYI(1, ("Rename to File by handle"));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
+			(void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 6;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+	rename_info = (struct set_file_rename *) data_offset;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	byte_count = 3 /* pad */  + params;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	/* construct random name ".cifs_tmp<inodenum><mid>" */
+	rename_info->overwrite = cpu_to_le32(1);
+	rename_info->root_fid  = 0;
+	/* unicode only call */
+	if(target_name == NULL) {
+		sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
+	        len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
+	} else {
+		len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage);
+	}
+	rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
+	count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
+	byte_count += count;
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->Fid = netfid;
+	pSMB->InformationLevel =
+		cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
+                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1,("Send error in Rename (by file handle) = %d", rc));
+	}
+#ifdef CONFIG_CIFS_STATS
+	  else {
+		atomic_inc(&pTcon->num_t2renames);
+	}
+#endif
+	cifs_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
+		since file handle passed in no longer valid */
+
+	return rc;
+}
+
+int
+CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
+            const __u16 target_tid, const char *toName, const int flags,
+            const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	COPY_REQ *pSMB = NULL;
+	COPY_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len, name_len2;
+	__u16 count;
+
+	cFYI(1, ("In CIFSSMBCopy"));
+copyRetry:
+	rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
+			(void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->BufferFormat = 0x04;
+	pSMB->Tid2 = target_tid;
+
+	pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, 
+				fromName, 
+				PATH_MAX /* find define for this maxpathcomponent */,
+				nls_codepage);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+		pSMB->OldFileName[name_len] = 0x04;     /* pad */
+		/* protocol requires ASCII signature byte on Unicode string */
+		pSMB->OldFileName[name_len + 1] = 0x00;
+		name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
+				OldFileName[name_len + 2], toName, PATH_MAX,
+				nls_codepage);
+		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
+		name_len2 *= 2; /* convert to bytes */
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fromName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->OldFileName, fromName, name_len);
+		name_len2 = strnlen(toName, PATH_MAX);
+		name_len2++;    /* trailing null */
+		pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
+		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		name_len2++;    /* trailing null */
+		name_len2++;    /* signature byte */
+	}
+
+	count = 1 /* 1st signature byte */  + name_len + name_len2;
+	pSMB->hdr.smb_buf_length += count;
+	pSMB->ByteCount = cpu_to_le16(count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in copy = %d with %d files copied",
+			rc, le16_to_cpu(pSMBr->CopyCount)));
+	}
+	if (pSMB)
+		cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto copyRetry;
+
+	return rc;
+}
+
+int
+CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
+		      const char *fromName, const char *toName,
+		      const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	char *data_offset;
+	int name_len;
+	int name_len_target;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count;
+
+	cFYI(1, ("In Symlink Unix style"));
+createSymLinkRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fromName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fromName, name_len);
+	}
+	params = 6 + name_len;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len_target =
+		    cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len_target++;	/* trailing null */
+		name_len_target *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len_target = strnlen(toName, PATH_MAX);
+		name_len_target++;	/* trailing null */
+		strncpy(data_offset, toName, name_len_target);
+	}
+
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	/* BB find exact max on data count below from sess */
+	pSMB->MaxDataCount = cpu_to_le16(1000);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	byte_count = 3 /* pad */  + params + name_len_target;
+	pSMB->DataCount = cpu_to_le16(name_len_target);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1,
+		     ("Send error in SetPathInfo (create symlink) = %d",
+		      rc));
+	}
+
+	if (pSMB)
+		cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto createSymLinkRetry;
+
+	return rc;
+}
+
+int
+CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
+		       const char *fromName, const char *toName,
+		       const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	char *data_offset;
+	int name_len;
+	int name_len_target;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count;
+
+	cFYI(1, ("In Create Hard link Unix style"));
+createHardLinkRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX
+					 /* find define for this maxpathcomponent */
+					 , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(toName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, toName, name_len);
+	}
+	params = 6 + name_len;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len_target =
+		    cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len_target++;	/* trailing null */
+		name_len_target *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len_target = strnlen(fromName, PATH_MAX);
+		name_len_target++;	/* trailing null */
+		strncpy(data_offset, fromName, name_len_target);
+	}
+
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	/* BB find exact max on data count below from sess*/
+	pSMB->MaxDataCount = cpu_to_le16(1000);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	byte_count = 3 /* pad */  + params + name_len_target;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->DataCount = cpu_to_le16(name_len_target);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
+	}
+
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto createHardLinkRetry;
+
+	return rc;
+}
+
+int
+CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
+		   const char *fromName, const char *toName,
+		   const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	NT_RENAME_REQ *pSMB = NULL;
+	RENAME_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len, name_len2;
+	__u16 count;
+
+	cFYI(1, ("In CIFSCreateHardLink"));
+winCreateHardLinkRetry:
+
+	rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+	pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
+	pSMB->ClusterCount = 0;
+
+	pSMB->BufferFormat = 0x04;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+		pSMB->OldFileName[name_len] = 0;	/* pad */
+		pSMB->OldFileName[name_len + 1] = 0x04; 
+		name_len2 =
+		    cifs_strtoUCS((wchar_t *) & pSMB->
+				  OldFileName[name_len + 2], toName, PATH_MAX,
+				  nls_codepage);
+		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
+		name_len2 *= 2;	/* convert to bytes */
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fromName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->OldFileName, fromName, name_len);
+		name_len2 = strnlen(toName, PATH_MAX);
+		name_len2++;	/* trailing null */
+		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
+		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		name_len2++;	/* trailing null */
+		name_len2++;	/* signature byte */
+	}
+
+	count = 1 /* string type byte */  + name_len + name_len2;
+	pSMB->hdr.smb_buf_length += count;
+	pSMB->ByteCount = cpu_to_le16(count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
+	}
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto winCreateHardLinkRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
+			const unsigned char *searchName,
+			char *symlinkinfo, const int buflen,
+			const struct nls_table *nls_codepage)
+{
+/* SMB_QUERY_FILE_UNIX_LINK */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
+
+querySymLinkRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	/* BB find exact max data count below from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(4000);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
+	} else {
+		/* decode response */
+
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		if (rc || (pSMBr->ByteCount < 2))
+		/* BB also check enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+
+			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+				name_len = UniStrnlen((wchar_t *) ((char *)
+					&pSMBr->hdr.Protocol +data_offset),
+					min_t(const int, buflen,count) / 2);
+				cifs_strfromUCS_le(symlinkinfo,
+					(wchar_t *) ((char *)&pSMBr->hdr.Protocol +
+						data_offset),
+					name_len, nls_codepage);
+			} else {
+				strncpy(symlinkinfo,
+					(char *) &pSMBr->hdr.Protocol + 
+						data_offset,
+					min_t(const int, buflen, count));
+			}
+			symlinkinfo[buflen] = 0;
+	/* just in case so calling code does not go off the end of buffer */
+		}
+	}
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto querySymLinkRetry;
+	return rc;
+}
+
+int
+CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
+			const unsigned char *searchName,
+			char *symlinkinfo, const int buflen,__u16 fid,
+			const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	struct smb_com_transaction_ioctl_req * pSMB;
+	struct smb_com_transaction_ioctl_rsp * pSMBr;
+
+	cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
+	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->TotalParameterCount = 0 ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le32(2);
+	/* BB find exact data count max from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le32(4000);
+	pSMB->MaxSetupCount = 4;
+	pSMB->Reserved = 0;
+	pSMB->ParameterOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 4;
+	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
+	pSMB->IsFsctl = 1; /* FSCTL */
+	pSMB->IsRootFlag = 0;
+	pSMB->Fid = fid; /* file handle always le */
+	pSMB->ByteCount = 0;
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
+	} else {		/* decode response */
+		__u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
+		__u32 data_count = le32_to_cpu(pSMBr->DataCount);
+		if ((pSMBr->ByteCount < 2) || (data_offset > 512))
+		/* BB also check enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			if(data_count && (data_count < 2048)) {
+				char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
+
+				struct reparse_data * reparse_buf = (struct reparse_data *)
+					((char *)&pSMBr->hdr.Protocol + data_offset);
+				if((char*)reparse_buf >= end_of_smb) {
+					rc = -EIO;
+					goto qreparse_out;
+				}
+				if((reparse_buf->LinkNamesBuf + 
+					reparse_buf->TargetNameOffset +
+					reparse_buf->TargetNameLen) >
+						end_of_smb) {
+					cFYI(1,("reparse buf extended beyond SMB"));
+					rc = -EIO;
+					goto qreparse_out;
+				}
+				
+				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+					name_len = UniStrnlen((wchar_t *)
+							(reparse_buf->LinkNamesBuf + 
+							reparse_buf->TargetNameOffset),
+							min(buflen/2, reparse_buf->TargetNameLen / 2)); 
+					cifs_strfromUCS_le(symlinkinfo,
+						(wchar_t *) (reparse_buf->LinkNamesBuf + 
+						reparse_buf->TargetNameOffset),
+						name_len, nls_codepage);
+				} else { /* ASCII names */
+					strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
+						reparse_buf->TargetNameOffset, 
+						min_t(const int, buflen, reparse_buf->TargetNameLen));
+				}
+			} else {
+				rc = -EIO;
+				cFYI(1,("Invalid return data count on get reparse info ioctl"));
+			}
+			symlinkinfo[buflen] = 0; /* just in case so the caller
+					does not go off the end of the buffer */
+			cFYI(1,("readlink result - %s ",symlinkinfo));
+		}
+	}
+qreparse_out:
+	if (pSMB)
+		cifs_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
+		since file handle passed in no longer valid */
+
+	return rc;
+}
+
+#ifdef CONFIG_CIFS_POSIX
+
+/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
+static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
+{
+	/* u8 cifs fields do not need le conversion */
+	ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
+	ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
+	ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
+	/* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
+
+	return;
+}
+
+/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
+static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area)
+{
+	int size =  0;
+	int i;
+	__u16 count;
+	struct cifs_posix_ace * pACE;
+	struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
+	posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
+
+	if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
+		return -EOPNOTSUPP;
+
+	if(acl_type & ACL_TYPE_ACCESS) {
+		count = le16_to_cpu(cifs_acl->access_entry_count);
+		pACE = &cifs_acl->ace_array[0];
+		size = sizeof(struct cifs_posix_acl);
+		size += sizeof(struct cifs_posix_ace) * count;
+		/* check if we would go beyond end of SMB */
+		if(size_of_data_area < size) {
+			cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
+			return -EINVAL;
+		}
+	} else if(acl_type & ACL_TYPE_DEFAULT) {
+		count = le16_to_cpu(cifs_acl->access_entry_count);
+		size = sizeof(struct cifs_posix_acl);
+		size += sizeof(struct cifs_posix_ace) * count;
+/* skip past access ACEs to get to default ACEs */
+		pACE = &cifs_acl->ace_array[count];
+		count = le16_to_cpu(cifs_acl->default_entry_count);
+		size += sizeof(struct cifs_posix_ace) * count;
+		/* check if we would go beyond end of SMB */
+		if(size_of_data_area < size)
+			return -EINVAL;
+	} else {
+		/* illegal type */
+		return -EINVAL;
+	}
+
+	size = posix_acl_xattr_size(count);
+	if((buflen == 0) || (local_acl == NULL)) {
+		/* used to query ACL EA size */				
+	} else if(size > buflen) {
+		return -ERANGE;
+	} else /* buffer big enough */ {
+		local_acl->a_version = POSIX_ACL_XATTR_VERSION;
+		for(i = 0;i < count ;i++) {
+			cifs_convert_ace(&local_acl->a_entries[i],pACE);
+			pACE ++;
+		}
+	}
+	return size;
+}
+
+static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
+			const posix_acl_xattr_entry * local_ace)
+{
+	__u16 rc = 0; /* 0 = ACL converted ok */
+
+	cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
+	cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
+	/* BB is there a better way to handle the large uid? */
+	if(local_ace->e_id == -1) {
+	/* Probably no need to le convert -1 on any arch but can not hurt */
+		cifs_ace->cifs_uid = cpu_to_le64(-1);
+	} else 
+		cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
+        /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
+	return rc;
+}
+
+/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
+static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
+		const int acl_type)
+{
+	__u16 rc = 0;
+        struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
+        posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
+	int count;
+	int i;
+
+	if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
+		return 0;
+
+	count = posix_acl_xattr_count((size_t)buflen);
+	cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
+		count,buflen,local_acl->a_version));
+	if(local_acl->a_version != 2) {
+		cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
+		return 0;
+	}
+	cifs_acl->version = cpu_to_le16(1);
+	if(acl_type == ACL_TYPE_ACCESS) 
+		cifs_acl->access_entry_count = count;
+	else if(acl_type == ACL_TYPE_DEFAULT)
+		cifs_acl->default_entry_count = count;
+	else {
+		cFYI(1,("unknown ACL type %d",acl_type));
+		return 0;
+	}
+	for(i=0;i<count;i++) {
+		rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
+					&local_acl->a_entries[i]);
+		if(rc != 0) {
+			/* ACE not converted */
+			break;
+		}
+	}
+	if(rc == 0) {
+		rc = (__u16)(count * sizeof(struct cifs_posix_ace));
+		rc += sizeof(struct cifs_posix_acl);
+		/* BB add check to make sure ACL does not overflow SMB */
+	}
+	return rc;
+}
+
+int
+CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
+                        const unsigned char *searchName,
+                        char *acl_inf, const int buflen, const int acl_type,
+                        const struct nls_table *nls_codepage)
+{
+/* SMB_QUERY_POSIX_ACL */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	__u16 params, byte_count;
+                                                                                                                                             
+	cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
+
+queryAclRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		(void **) &pSMBr);
+	if (rc)
+		return rc;
+                                                                                                                                             
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+			cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+				, nls_codepage);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+		pSMB->FileName[name_len] = 0;
+		pSMB->FileName[name_len+1] = 0;
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+        /* BB find exact max data count below from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(4000);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(
+		offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
+	} else {
+		/* decode response */
+ 
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		if (rc || (pSMBr->ByteCount < 2))
+		/* BB also check enough total bytes returned */
+			rc = -EIO;      /* bad smb */
+		else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+			rc = cifs_copy_posix_acl(acl_inf,
+				(char *)&pSMBr->hdr.Protocol+data_offset,
+				buflen,acl_type,count);
+		}
+	}
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto queryAclRetry;
+	return rc;
+}
+
+int
+CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
+                        const unsigned char *fileName,
+                        const char *local_acl, const int buflen, const int acl_type,
+                        const struct nls_table *nls_codepage)
+{
+	struct smb_com_transaction2_spi_req *pSMB = NULL;
+	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+	char *parm_data;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count, data_count, param_offset, offset;
+
+	cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
+setAclRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+	if (rc)
+		return rc;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+			cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
+				, nls_codepage);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+	params = 6 + name_len;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+	parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+
+	/* convert to on the wire format for POSIX ACL */
+	data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
+
+	if(data_count == 0) {
+		rc = -EOPNOTSUPP;
+		goto setACLerrorExit;
+	}
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
+	byte_count = 3 /* pad */  + params + data_count;
+	pSMB->DataCount = cpu_to_le16(data_count);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Set POSIX ACL returned %d", rc));
+	}
+
+setACLerrorExit:
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto setAclRetry;
+	return rc;
+}
+
+#endif
+
+int
+CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
+		 const unsigned char *searchName,
+		 FILE_ALL_INFO * pFindData,
+		 const struct nls_table *nls_codepage)
+{
+/* level 263 SMB_QUERY_FILE_ALL_INFO */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	__u16 params, byte_count;
+
+/* cFYI(1, ("In QPathInfo path %s", searchName)); */
+QPathInfoRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QPathInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 40)) 
+			rc = -EIO;	/* bad smb */
+		else if (pFindData){
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			memcpy((char *) pFindData,
+			       (char *) &pSMBr->hdr.Protocol +
+			       data_offset, sizeof (FILE_ALL_INFO));
+		} else
+		    rc = -ENOMEM;
+	}
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto QPathInfoRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
+		     const unsigned char *searchName,
+		     FILE_UNIX_BASIC_INFO * pFindData,
+		     const struct nls_table *nls_codepage)
+{
+/* SMB_QUERY_FILE_UNIX_BASIC */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned = 0;
+	int name_len;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
+UnixQPathInfoRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(4000); 
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QPathInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
+			rc = -EIO;	/* bad smb */
+		} else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			memcpy((char *) pFindData,
+			       (char *) &pSMBr->hdr.Protocol +
+			       data_offset,
+			       sizeof (FILE_UNIX_BASIC_INFO));
+		}
+	}
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto UnixQPathInfoRetry;
+
+	return rc;
+}
+
+#if 0  /* function unused at present */
+int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
+	       const char *searchName, FILE_ALL_INFO * findData,
+	       const struct nls_table *nls_codepage)
+{
+/* level 257 SMB_ */
+	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
+	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In FindUnique"));
+findUniqueRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 12 + name_len /* includes null */ ;
+	pSMB->TotalDataCount = 0;	/* no EAs */
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(
+         offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;	/* one byte, no need to le convert */
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+	pSMB->SearchCount = cpu_to_le16(16);	/* BB increase */
+	pSMB->SearchFlags = cpu_to_le16(1);
+	pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+	pSMB->SearchStorageType = 0;	/* BB what should we set this to? BB */
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	if (rc) {
+		cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
+	} else {		/* decode response */
+
+		/* BB fill in */
+	}
+
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto findUniqueRetry;
+
+	return rc;
+}
+#endif /* end unused (temporarily) function */
+
+/* xid, tcon, searchName and codepage are input parms, rest are returned */
+int
+CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
+	      const char *searchName, 
+	      const struct nls_table *nls_codepage,
+	      __u16 *	pnetfid,
+	      struct cifs_search_info * psrch_inf)
+{
+/* level 257 SMB_ */
+	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
+	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
+	T2_FFIRST_RSP_PARMS * parms;
+	int rc = 0;
+	int bytes_returned = 0;
+	int name_len;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In FindFirst"));
+
+findFirstRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName,
+				 PATH_MAX, nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+		pSMB->FileName[name_len] = 0; /* null terminate just in case */
+		pSMB->FileName[name_len+1] = 0;
+	} else {	/* BB add check for overrun of SMB buf BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+/* BB fix here and in unicode clause above ie
+		if(name_len > buffersize-header)
+			free buffer exit; BB */
+		strncpy(pSMB->FileName, searchName, name_len);
+		pSMB->FileName[name_len] = 0; /* just in case */
+	}
+
+	params = 12 + name_len /* includes null */ ;
+	pSMB->TotalDataCount = 0;	/* no EAs */
+	pSMB->MaxParameterCount = cpu_to_le16(10);
+	pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
+					  MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(
+	  offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;	/* one byte, no need to make endian neutral */
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+	pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
+	pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
+		CIFS_SEARCH_RETURN_RESUME);
+	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
+
+	/* BB what should we set StorageType to? Does it matter? BB */
+	pSMB->SearchStorageType = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+		/* BB Add code to handle unsupported level rc */
+		cFYI(1, ("Error in FindFirst = %d", rc));
+
+		if (pSMB)
+			cifs_buf_release(pSMB);
+
+		/* BB eventually could optimize out free and realloc of buf */
+		/*    for this case */
+		if (rc == -EAGAIN)
+			goto findFirstRetry;
+	} else { /* decode response */
+		/* BB remember to free buffer if error BB */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		if(rc == 0) {
+			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+				psrch_inf->unicode = TRUE;
+			else
+				psrch_inf->unicode = FALSE;
+
+			psrch_inf->ntwrk_buf_start = (char *)pSMBr;
+			psrch_inf->srch_entries_start = 
+				(char *) &pSMBr->hdr.Protocol + 
+					le16_to_cpu(pSMBr->t2.DataOffset);
+
+			parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
+			       le16_to_cpu(pSMBr->t2.ParameterOffset));
+
+			if(parms->EndofSearch)
+				psrch_inf->endOfSearch = TRUE;
+			else
+				psrch_inf->endOfSearch = FALSE;
+
+			psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
+			psrch_inf->index_of_last_entry = 
+				psrch_inf->entries_in_buffer;
+/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry));  */
+			*pnetfid = parms->SearchHandle;
+		} else {
+			cifs_buf_release(pSMB);
+		}
+	}
+
+	return rc;
+}
+
+int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
+            __u16 searchHandle, struct cifs_search_info * psrch_inf)
+{
+	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
+	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
+	T2_FNEXT_RSP_PARMS * parms;
+	char *response_data;
+	int rc = 0;
+	int bytes_returned, name_len;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In FindNext"));
+
+	if(psrch_inf->endOfSearch == TRUE)
+		return -ENOENT;
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		(void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 14;    /* includes 2 bytes of null string, converted to LE below */
+	byte_count = 0;
+	pSMB->TotalDataCount = 0;       /* no EAs */
+	pSMB->MaxParameterCount = cpu_to_le16(8);
+	pSMB->MaxDataCount =
+            cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =  cpu_to_le16(
+	      offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
+	pSMB->SearchHandle = searchHandle;      /* always kept as le */
+	pSMB->SearchCount =
+		cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
+	/* test for Unix extensions */
+/*	if (tcon->ses->capabilities & CAP_UNIX) {
+		pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
+		psrch_inf->info_level = SMB_FIND_FILE_UNIX;
+	} else {
+		pSMB->InformationLevel =
+		   cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+		psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
+	} */
+	pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
+	pSMB->ResumeKey = psrch_inf->resume_key;
+	pSMB->SearchFlags =
+	      cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
+
+	name_len = psrch_inf->resume_name_len;
+	params += name_len;
+	if(name_len < PATH_MAX) {
+		memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
+		byte_count += name_len;
+	} else {
+		rc = -EINVAL;
+		goto FNext2_err_exit;
+	}
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+                                                                                              
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+                                                                                              
+	if (rc) {
+		if (rc == -EBADF) {
+			psrch_inf->endOfSearch = TRUE;
+			rc = 0; /* search probably was closed at end of search above */
+		} else
+			cFYI(1, ("FindNext returned = %d", rc));
+	} else {                /* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		
+		if(rc == 0) {
+			/* BB fixme add lock for file (srch_info) struct here */
+			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+				psrch_inf->unicode = TRUE;
+			else
+				psrch_inf->unicode = FALSE;
+			response_data = (char *) &pSMBr->hdr.Protocol +
+			       le16_to_cpu(pSMBr->t2.ParameterOffset);
+			parms = (T2_FNEXT_RSP_PARMS *)response_data;
+			response_data = (char *)&pSMBr->hdr.Protocol +
+				le16_to_cpu(pSMBr->t2.DataOffset);
+			cifs_buf_release(psrch_inf->ntwrk_buf_start);
+			psrch_inf->srch_entries_start = response_data;
+			psrch_inf->ntwrk_buf_start = (char *)pSMB;
+			if(parms->EndofSearch)
+				psrch_inf->endOfSearch = TRUE;
+			else
+				psrch_inf->endOfSearch = FALSE;
+                                                                                              
+			psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
+			psrch_inf->index_of_last_entry +=
+				psrch_inf->entries_in_buffer;
+/*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
+
+			/* BB fixme add unlock here */
+		}
+
+	}
+
+	/* BB On error, should we leave previous search buf (and count and
+	last entry fields) intact or free the previous one? */
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls
+	since file handle passed in no longer valid */
+FNext2_err_exit:
+	if (rc != 0)
+		cifs_buf_release(pSMB);
+                                                                                              
+	return rc;
+}
+
+int
+CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
+{
+	int rc = 0;
+	FINDCLOSE_REQ *pSMB = NULL;
+	CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
+	int bytes_returned;
+
+	cFYI(1, ("In CIFSSMBFindClose"));
+	rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
+
+	/* no sense returning error if session restarted
+		as file handle has been closed */
+	if(rc == -EAGAIN)
+		return 0;
+	if (rc)
+		return rc;
+
+	pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
+	pSMB->FileID = searchHandle;
+	pSMB->ByteCount = 0;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("Send error in FindClose = %d", rc));
+	}
+	cifs_small_buf_release(pSMB);
+
+	/* Since session is dead, search handle closed on server already */
+	if (rc == -EAGAIN)
+		rc = 0;
+
+	return rc;
+}
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+int
+CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
+                const unsigned char *searchName,
+                __u64 * inode_number,
+                const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int name_len, bytes_returned;
+	__u16 params, byte_count;
+
+	cFYI(1,("In GetSrvInodeNum for %s",searchName));
+	if(tcon == NULL)
+		return -ENODEV; 
+
+GetInodeNumberRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+			cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 
+				PATH_MAX,nls_codepage);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	/* BB find exact max data count below from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(4000);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+		struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+		(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("error %d in QueryInternalInfo", rc));
+	} else {
+		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		if (rc || (pSMBr->ByteCount < 2))
+		/* BB also check enough total bytes returned */
+			/* If rc should we check for EOPNOSUPP and
+			disable the srvino flag? or in caller? */
+			rc = -EIO;      /* bad smb */
+                else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+			struct file_internal_info * pfinfo;
+			/* BB Do we need a cast or hash here ? */
+			if(count < 8) {
+				cFYI(1, ("Illegal size ret in QryIntrnlInf"));
+				rc = -EIO;
+				goto GetInodeNumOut;
+			}
+			pfinfo = (struct file_internal_info *)
+				(data_offset + (char *) &pSMBr->hdr.Protocol);
+			*inode_number = pfinfo->UniqueId;
+		}
+	}
+GetInodeNumOut:
+	cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto GetInodeNumberRetry;
+	return rc;
+}
+#endif /* CIFS_EXPERIMENTAL */
+
+int
+CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
+		const unsigned char *searchName,
+		unsigned char **targetUNCs,
+		unsigned int *number_of_UNC_in_array,
+		const struct nls_table *nls_codepage)
+{
+/* TRANS2_GET_DFS_REFERRAL */
+	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
+	TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
+	struct dfs_referral_level_3 * referrals = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	unsigned int i;
+	char * temp;
+	__u16 params, byte_count;
+	*number_of_UNC_in_array = 0;
+	*targetUNCs = NULL;
+
+	cFYI(1, ("In GetDFSRefer the path %s", searchName));
+	if (ses == NULL)
+		return -ENODEV;
+getDFSRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->hdr.Tid = ses->ipc_tid;
+	pSMB->hdr.Uid = ses->Suid;
+	if (ses->capabilities & CAP_STATUS32) {
+		pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		pSMB->hdr.Flags2 |= SMBFLG2_DFS;
+	}
+
+	if (ses->capabilities & CAP_UNICODE) {
+		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
+				  searchName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->RequestFileName, searchName, name_len);
+	}
+
+	params = 2 /* level */  + name_len /*includes null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->MaxParameterCount = 0;
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
+	byte_count = params + 3 /* pad */ ;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->MaxReferralLevel = cpu_to_le16(3);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in GetDFSRefer = %d", rc));
+	} else {		/* decode response */
+/* BB Add logic to parse referrals here */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
+			rc = -EIO;      /* bad smb */
+		else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
+			__u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
+
+			cFYI(1,
+			     ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
+			      pSMBr->ByteCount, data_offset));
+			referrals = 
+			    (struct dfs_referral_level_3 *) 
+					(8 /* sizeof start of data block */ +
+					data_offset +
+					(char *) &pSMBr->hdr.Protocol); 
+			cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
+				le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
+			/* BB This field is actually two bytes in from start of
+			   data block so we could do safety check that DataBlock
+			   begins at address of pSMBr->NumberOfReferrals */
+			*number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
+
+			/* BB Fix below so can return more than one referral */
+			if(*number_of_UNC_in_array > 1)
+				*number_of_UNC_in_array = 1;
+
+			/* get the length of the strings describing refs */
+			name_len = 0;
+			for(i=0;i<*number_of_UNC_in_array;i++) {
+				/* make sure that DfsPathOffset not past end */
+				__u16 offset = le16_to_cpu(referrals->DfsPathOffset);
+				if (offset > data_count) {
+					/* if invalid referral, stop here and do 
+					not try to copy any more */
+					*number_of_UNC_in_array = i;
+					break;
+				} 
+				temp = ((char *)referrals) + offset;
+
+				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+					name_len += UniStrnlen((wchar_t *)temp,data_count);
+				} else {
+					name_len += strnlen(temp,data_count);
+				}
+				referrals++;
+				/* BB add check that referral pointer does not fall off end PDU */
+				
+			}
+			/* BB add check for name_len bigger than bcc */
+			*targetUNCs = 
+				kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
+			if(*targetUNCs == NULL) {
+				rc = -ENOMEM;
+				goto GetDFSRefExit;
+			}
+			/* copy the ref strings */
+			referrals =  
+			    (struct dfs_referral_level_3 *) 
+					(8 /* sizeof data hdr */ +
+					data_offset + 
+					(char *) &pSMBr->hdr.Protocol);
+
+			for(i=0;i<*number_of_UNC_in_array;i++) {
+				temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
+				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+					cifs_strfromUCS_le(*targetUNCs,
+						(wchar_t *) temp, name_len, nls_codepage);
+				} else {
+					strncpy(*targetUNCs,temp,name_len);
+				}
+				/*  BB update target_uncs pointers */
+				referrals++;
+			}
+			temp = *targetUNCs;
+			temp[name_len] = 0;
+		}
+
+	}
+GetDFSRefExit:
+	if (pSMB)
+		cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto getDFSRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
+	       struct kstatfs *FSData, const struct nls_table *nls_codepage)
+{
+/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QFSInfo"));
+QFSInfoRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("Send error in QFSInfo = %d", rc));
+	} else {		/* decode response */
+                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			cFYI(1,
+				("Decoding qfsinfo response.  BCC: %d  Offset %d",
+				pSMBr->ByteCount, data_offset));
+
+			response_data =
+			    (FILE_SYSTEM_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 data_offset);
+			FSData->f_bsize =
+			    le32_to_cpu(response_data->BytesPerSector) *
+			    le32_to_cpu(response_data->
+					SectorsPerAllocationUnit);
+			FSData->f_blocks =
+			    le64_to_cpu(response_data->TotalAllocationUnits);
+			FSData->f_bfree = FSData->f_bavail =
+			    le64_to_cpu(response_data->FreeAllocationUnits);
+			cFYI(1,
+			     ("Blocks: %lld  Free: %lld Block size %ld",
+			      (unsigned long long)FSData->f_blocks,
+			      (unsigned long long)FSData->f_bfree,
+			      FSData->f_bsize));
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QFSInfoRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
+			const struct nls_table *nls_codepage)
+{
+/* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QFSAttributeInfo"));
+QFSAttributeRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 13)) {	/* BB also check enough bytes returned */
+			rc = -EIO;	/* bad smb */
+		} else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			response_data =
+			    (FILE_SYSTEM_ATTRIBUTE_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 data_offset);
+			memcpy(&tcon->fsAttrInfo, response_data,
+			       sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QFSAttributeRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
+		     const struct nls_table *nls_codepage)
+{
+/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_DEVICE_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QFSDeviceInfo"));
+QFSDeviceRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
+			rc = -EIO;	/* bad smb */
+		else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			response_data =
+			    (FILE_SYSTEM_DEVICE_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 data_offset);
+			memcpy(&tcon->fsDevInfo, response_data,
+			       sizeof (FILE_SYSTEM_DEVICE_INFO));
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QFSDeviceRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+		   const struct nls_table *nls_codepage)
+{
+/* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_UNIX_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QFSUnixInfo"));
+QFSUnixRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(100);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
+        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 13)) {
+			rc = -EIO;	/* bad smb */
+		} else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			response_data =
+			    (FILE_SYSTEM_UNIX_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 data_offset);
+			memcpy(&tcon->fsUnixInfo, response_data,
+			       sizeof (FILE_SYSTEM_UNIX_INFO));
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QFSUnixRetry;
+
+
+	return rc;
+}
+
+
+int
+CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
+		   struct kstatfs *FSData, const struct nls_table *nls_codepage)
+{
+/* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_POSIX_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In QFSPosixInfo"));
+QFSPosixRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	params = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(100);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	byte_count = params + 1 /* pad */ ;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
+        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		if (rc || (pSMBr->ByteCount < 13)) {
+			rc = -EIO;	/* bad smb */
+		} else {
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			response_data =
+			    (FILE_SYSTEM_POSIX_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 data_offset);
+			FSData->f_bsize =
+					le32_to_cpu(response_data->BlockSize);
+			FSData->f_blocks =
+					le64_to_cpu(response_data->TotalBlocks);
+			FSData->f_bfree =
+			    le64_to_cpu(response_data->BlocksAvail);
+			if(response_data->UserBlocksAvail == -1) {
+				FSData->f_bavail = FSData->f_bfree;
+			} else {
+				FSData->f_bavail =
+					le64_to_cpu(response_data->UserBlocksAvail);
+			}
+			if(response_data->TotalFileNodes != -1)
+				FSData->f_files =
+					le64_to_cpu(response_data->TotalFileNodes);
+			if(response_data->FreeFileNodes != -1)
+				FSData->f_ffree =
+					le64_to_cpu(response_data->FreeFileNodes);
+		}
+	}
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto QFSPosixRetry;
+
+	return rc;
+}
+
+
+/* We can not use write of zero bytes trick to 
+   set file size due to need for large file support.  Also note that 
+   this SetPathInfo is preferred to SetFileInfo based method in next 
+   routine which is only needed to work around a sharing violation bug
+   in Samba which this routine can run into */
+
+int
+CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+	      __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
+{
+	struct smb_com_transaction2_spi_req *pSMB = NULL;
+	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+	struct file_end_of_file_info *parm_data;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, byte_count, data_count, param_offset, offset;
+
+	cFYI(1, ("In SetEOF"));
+SetEOFRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+	params = 6 + name_len;
+	data_count = sizeof (struct file_end_of_file_info);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+	if(SetAllocation) {
+        	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+	            pSMB->InformationLevel =
+                	cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+        	else
+	            pSMB->InformationLevel =
+        	        cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+	} else /* Set File Size */  {    
+	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+	    else
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+	}
+
+	parm_data =
+	    (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
+				       offset);
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	byte_count = 3 /* pad */  + params + data_count;
+	pSMB->DataCount = cpu_to_le16(data_count);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	parm_data->FileSize = cpu_to_le64(size);
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("SetPathInfo (file size) returned %d", rc));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto SetEOFRetry;
+
+	return rc;
+}
+
+int
+CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
+                   __u16 fid, __u32 pid_of_opener, int SetAllocation)
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	char *data_offset;
+	struct file_end_of_file_info *parm_data;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count, count;
+
+	cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
+			(long long)size));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+    
+	params = 6;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;	
+
+	count = sizeof(struct file_end_of_file_info);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB PDU from sess */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	parm_data =
+		(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
+			offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	parm_data->FileSize = cpu_to_le64(size);
+	pSMB->Fid = fid;
+	if(SetAllocation) {
+		if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+			pSMB->InformationLevel =
+				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+		else
+			pSMB->InformationLevel =
+				cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+	} else /* Set File Size */  {    
+	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+	    else
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+	}
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1,
+		     ("Send error in SetFileInfo (SetFileSize) = %d",
+		      rc));
+	}
+
+	if (pSMB)
+		cifs_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls 
+		since file handle passed in no longer valid */
+
+	return rc;
+}
+
+/* Some legacy servers such as NT4 require that the file times be set on 
+   an open handle, rather than by pathname - this is awkward due to
+   potential access conflicts on the open, but it is unavoidable for these
+   old servers since the only other choice is to go from 100 nanosecond DCE
+   time and resort to the original setpathinfo level which takes the ancient
+   DOS time format with 2 second granularity */
+int
+CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
+                   __u16 fid)
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	char *data_offset;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, offset, byte_count, count;
+
+	cFYI(1, ("Set Times (via SetFileInfo)"));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	/* At this point there is no need to override the current pid
+	with the pid of the opener, but that could change if we someday
+	use an existing handle (rather than opening one on the fly) */
+	/* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+	pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
+    
+	params = 6;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+	offset = param_offset + params;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
+
+	count = sizeof (FILE_BASIC_INFO);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB PDU from sess */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->Fid = fid;
+	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
+	else
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
+	}
+
+	cifs_buf_release(pSMB);
+
+	/* Note: On -EAGAIN error only caller can retry on handle based calls 
+		since file handle passed in no longer valid */
+
+	return rc;
+}
+
+
+int
+CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+		const FILE_BASIC_INFO * data, 
+		const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	char *data_offset;
+	__u16 params, param_offset, offset, byte_count, count;
+
+	cFYI(1, ("In SetTimes"));
+
+SetTimesRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+
+	params = 6 + name_len;
+	count = sizeof (FILE_BASIC_INFO);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
+	else
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("SetPathInfo (times) returned %d", rc));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto SetTimesRetry;
+
+	return rc;
+}
+
+/* Can not be used to set time stamps yet (due to old DOS time format) */
+/* Can be used to set attributes */
+#if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
+	  handling it anyway and NT4 was what we thought it would be needed for
+	  Do not delete it until we prove whether needed for Win9x though */
+int
+CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
+		__u16 dos_attrs, const struct nls_table *nls_codepage)
+{
+	SETATTR_REQ *pSMB = NULL;
+	SETATTR_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("In SetAttrLegacy"));
+
+SetAttrLgcyRetry:
+	rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+			cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 
+				PATH_MAX, nls_codepage);
+		name_len++;     /* trailing null */
+		name_len *= 2;
+	} else {                /* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;     /* trailing null */
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	pSMB->attr = cpu_to_le16(dos_attrs);
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += name_len + 1;
+	pSMB->ByteCount = cpu_to_le16(name_len + 1);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Error in LegacySetAttr = %d", rc));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto SetAttrLgcyRetry;
+
+	return rc;
+}
+#endif /* temporarily unneeded SetAttr legacy function */
+
+int
+CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
+		    char *fileName, __u64 mode, __u64 uid, __u64 gid,
+		    dev_t device, const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	FILE_UNIX_BASIC_INFO *data_offset;
+	__u16 params, param_offset, offset, count, byte_count;
+
+	cFYI(1, ("In SetUID/GID/Mode"));
+setPermsRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+
+	params = 6 + name_len;
+	count = sizeof (FILE_UNIX_BASIC_INFO);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+	data_offset =
+	    (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
+				      offset);
+	memset(data_offset, 0, count);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	data_offset->Uid = cpu_to_le64(uid);
+	data_offset->Gid = cpu_to_le64(gid);
+	/* better to leave device as zero when it is  */
+	data_offset->DevMajor = cpu_to_le64(MAJOR(device));
+	data_offset->DevMinor = cpu_to_le64(MINOR(device));
+	data_offset->Permissions = cpu_to_le64(mode);
+    
+	if(S_ISREG(mode))
+		data_offset->Type = cpu_to_le32(UNIX_FILE);
+	else if(S_ISDIR(mode))
+		data_offset->Type = cpu_to_le32(UNIX_DIR);
+	else if(S_ISLNK(mode))
+		data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
+	else if(S_ISCHR(mode))
+		data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
+	else if(S_ISBLK(mode))
+		data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
+	else if(S_ISFIFO(mode))
+		data_offset->Type = cpu_to_le32(UNIX_FIFO);
+	else if(S_ISSOCK(mode))
+		data_offset->Type = cpu_to_le32(UNIX_SOCKET);
+
+
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("SetPathInfo (perms) returned %d", rc));
+	}
+
+	if (pSMB)
+		cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto setPermsRetry;
+	return rc;
+}
+
+int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
+			const int notify_subdirs, const __u16 netfid,
+			__u32 filter, const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	struct smb_com_transaction_change_notify_req * pSMB = NULL;
+	struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+	int bytes_returned;
+
+	cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
+	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->TotalParameterCount = 0 ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le32(2);
+	/* BB find exact data count max from sess structure BB */
+	pSMB->MaxDataCount = 0; /* same in little endian or be */
+	pSMB->MaxSetupCount = 4;
+	pSMB->Reserved = 0;
+	pSMB->ParameterOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 4; /* single byte does not need le conversion */
+	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	if(notify_subdirs)
+		pSMB->WatchTree = 1; /* one byte - no le conversion needed */
+	pSMB->Reserved2 = 0;
+	pSMB->CompletionFilter = cpu_to_le32(filter);
+	pSMB->Fid = netfid; /* file handle always le */
+	pSMB->ByteCount = 0;
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			(struct smb_hdr *) pSMBr, &bytes_returned, -1);
+	if (rc) {
+		cFYI(1, ("Error in Notify = %d", rc));
+	}
+	cifs_buf_release(pSMB);
+	return rc;	
+}
+#ifdef CONFIG_CIFS_XATTR
+ssize_t
+CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
+		 const unsigned char *searchName,
+		 char * EAData, size_t buf_size,
+		 const struct nls_table *nls_codepage)
+{
+		/* BB assumes one setup word */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	struct fea * temp_fea;
+	char * temp_ptr;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In Query All EAs path %s", searchName));
+QAllEAsRetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in QueryAllEAs = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		/* BB also check enough total bytes returned */
+		/* BB we need to improve the validity checking
+		of these trans2 responses */
+		if (rc || (pSMBr->ByteCount < 4)) 
+			rc = -EIO;	/* bad smb */
+	   /* else if (pFindData){
+			memcpy((char *) pFindData,
+			       (char *) &pSMBr->hdr.Protocol +
+			       data_offset, kl);
+		}*/ else {
+			/* check that length of list is not more than bcc */
+			/* check that each entry does not go beyond length
+			   of list */
+			/* check that each element of each entry does not
+			   go beyond end of list */
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			struct fealist * ea_response_data;
+			rc = 0;
+			/* validate_trans2_offsets() */
+			/* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+			ea_response_data = (struct fealist *)
+				(((char *) &pSMBr->hdr.Protocol) +
+				data_offset);
+			name_len = le32_to_cpu(ea_response_data->list_len);
+			cFYI(1,("ea length %d", name_len));
+			if(name_len <= 8) {
+			/* returned EA size zeroed at top of function */
+				cFYI(1,("empty EA list returned from server"));
+			} else {
+				/* account for ea list len */
+				name_len -= 4;
+				temp_fea = ea_response_data->list;
+				temp_ptr = (char *)temp_fea;
+				while(name_len > 0) {
+					__u16 value_len;
+					name_len -= 4;
+					temp_ptr += 4;
+					rc += temp_fea->name_len;
+				/* account for prefix user. and trailing null */
+					rc = rc + 5 + 1; 
+					if(rc<(int)buf_size) {
+						memcpy(EAData,"user.",5);
+						EAData+=5;
+						memcpy(EAData,temp_ptr,temp_fea->name_len);
+						EAData+=temp_fea->name_len;
+						/* null terminate name */
+						*EAData = 0;
+						EAData = EAData + 1;
+					} else if(buf_size == 0) {
+						/* skip copy - calc size only */
+					} else {
+						/* stop before overrun buffer */
+						rc = -ERANGE;
+						break;
+					}
+					name_len -= temp_fea->name_len;
+					temp_ptr += temp_fea->name_len;
+					/* account for trailing null */
+					name_len--;
+					temp_ptr++;
+					value_len = le16_to_cpu(temp_fea->value_len);
+					name_len -= value_len;
+					temp_ptr += value_len;
+					/* BB check that temp_ptr is still within smb BB*/
+				/* no trailing null to account for in value len */
+					/* go on to next EA */
+					temp_fea = (struct fea *)temp_ptr;
+				}
+			}
+		}
+	}
+	if (pSMB)
+		cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto QAllEAsRetry;
+
+	return (ssize_t)rc;
+}
+
+ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
+		const unsigned char * searchName,const unsigned char * ea_name,
+		unsigned char * ea_value, size_t buf_size, 
+		const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	struct fea * temp_fea;
+	char * temp_ptr;
+	__u16 params, byte_count;
+
+	cFYI(1, ("In Query EA path %s", searchName));
+QEARetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(searchName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	byte_count = params + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(params);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Send error in Query EA = %d", rc));
+	} else {		/* decode response */
+		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+		/* BB also check enough total bytes returned */
+		/* BB we need to improve the validity checking
+		of these trans2 responses */
+		if (rc || (pSMBr->ByteCount < 4)) 
+			rc = -EIO;	/* bad smb */
+	   /* else if (pFindData){
+			memcpy((char *) pFindData,
+			       (char *) &pSMBr->hdr.Protocol +
+			       data_offset, kl);
+		}*/ else {
+			/* check that length of list is not more than bcc */
+			/* check that each entry does not go beyond length
+			   of list */
+			/* check that each element of each entry does not
+			   go beyond end of list */
+			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+			struct fealist * ea_response_data;
+			rc = -ENODATA;
+			/* validate_trans2_offsets() */
+			/* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+			ea_response_data = (struct fealist *)
+				(((char *) &pSMBr->hdr.Protocol) +
+				data_offset);
+			name_len = le32_to_cpu(ea_response_data->list_len);
+			cFYI(1,("ea length %d", name_len));
+			if(name_len <= 8) {
+			/* returned EA size zeroed at top of function */
+				cFYI(1,("empty EA list returned from server"));
+			} else {
+				/* account for ea list len */
+				name_len -= 4;
+				temp_fea = ea_response_data->list;
+				temp_ptr = (char *)temp_fea;
+				/* loop through checking if we have a matching
+				name and then return the associated value */
+				while(name_len > 0) {
+					__u16 value_len;
+					name_len -= 4;
+					temp_ptr += 4;
+					value_len = le16_to_cpu(temp_fea->value_len);
+				/* BB validate that value_len falls within SMB, 
+				even though maximum for name_len is 255 */ 
+					if(memcmp(temp_fea->name,ea_name,
+						  temp_fea->name_len) == 0) {
+						/* found a match */
+						rc = value_len;
+				/* account for prefix user. and trailing null */
+						if(rc<=(int)buf_size) {
+							memcpy(ea_value,
+								temp_fea->name+temp_fea->name_len+1,
+								rc);
+							/* ea values, unlike ea names,
+							are not null terminated */
+						} else if(buf_size == 0) {
+						/* skip copy - calc size only */
+						} else {
+							/* stop before overrun buffer */
+							rc = -ERANGE;
+						}
+						break;
+					}
+					name_len -= temp_fea->name_len;
+					temp_ptr += temp_fea->name_len;
+					/* account for trailing null */
+					name_len--;
+					temp_ptr++;
+					name_len -= value_len;
+					temp_ptr += value_len;
+				/* no trailing null to account for in value len */
+					/* go on to next EA */
+					temp_fea = (struct fea *)temp_ptr;
+				}
+			} 
+		}
+	}
+	if (pSMB)
+		cifs_buf_release(pSMB);
+	if (rc == -EAGAIN)
+		goto QEARetry;
+
+	return (ssize_t)rc;
+}
+
+int
+CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+		const char * ea_name, const void * ea_value, 
+		const __u16 ea_value_len, const struct nls_table *nls_codepage)
+{
+	struct smb_com_transaction2_spi_req *pSMB = NULL;
+	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+	struct fealist *parm_data;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	__u16 params, param_offset, byte_count, offset, count;
+
+	cFYI(1, ("In SetEA"));
+SetEARetry:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fileName, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+
+	params = 6 + name_len;
+
+	/* done calculating parms using name_len of file name,
+	now use name_len to calculate length of ea name
+	we are going to create in the inode xattrs */
+	if(ea_name == NULL)
+		name_len = 0;
+	else
+		name_len = strnlen(ea_name,255);
+
+	count = sizeof(*parm_data) + ea_value_len + name_len + 1;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+	pSMB->InformationLevel =
+		cpu_to_le16(SMB_SET_FILE_EA);
+
+	parm_data =
+		(struct fealist *) (((char *) &pSMB->hdr.Protocol) +
+				       offset);
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+	pSMB->DataCount = cpu_to_le16(count);
+	parm_data->list_len = cpu_to_le32(count);
+	parm_data->list[0].EA_flags = 0;
+	/* we checked above that name len is less than 255 */
+	parm_data->list[0].name_len = (__u8)name_len;;
+	/* EA names are always ASCII */
+	if(ea_name)
+		strncpy(parm_data->list[0].name,ea_name,name_len);
+	parm_data->list[0].name[name_len] = 0;
+	parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
+	/* caller ensures that ea_value_len is less than 64K but
+	we need to ensure that it fits within the smb */
+
+	/*BB add length check that it would fit in negotiated SMB buffer size BB */
+	/* if(ea_value_len > buffer_size - 512 (enough for header)) */
+	if(ea_value_len)
+		memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
+
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count;
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("SetPathInfo (EA) returned %d", rc));
+	}
+
+	cifs_buf_release(pSMB);
+
+	if (rc == -EAGAIN)
+		goto SetEARetry;
+
+	return rc;
+}
+
+#endif