From c32e6f2ee387ccf4a7db34128662a870e413edad Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@gmail.com>
Date: Tue, 23 Jun 2015 01:25:12 -0500
Subject: [PATCH] [CIFS] add functions for cifs query info to fall back to

Some servers such as NetApp didn't support the normal info levels

Signed-off-by: Gregor Beck <gbeck@sernet.de>
---
 fs/cifs/cifsproto.h |  6 ++++
 fs/cifs/cifssmb.c   | 87 ++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 66 insertions(+), 27 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c63fd1d..5372046 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -249,6 +249,12 @@ extern int CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
 			    const char *search_Name, FILE_ALL_INFO *data,
 			    int legacy /* whether to use old info level */,
 			    const struct nls_table *nls_codepage, int remap);
+extern int CIFSSMBQPathInfoBasic(const unsigned int xid, struct cifs_tcon *tcon,
+				 const char *search_name, FILE_BASIC_INFO *data,
+				 const struct nls_table *nls_codepage, int remap);
+extern int CIFSSMBQPathInfoStandard(const unsigned int xid, struct cifs_tcon *tcon,
+				    const char *search_name, FILE_STANDARD_INFO *data,
+				    const struct nls_table *nls_codepage, int remap);
 extern int SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
 			       const char *search_name, FILE_ALL_INFO *data,
 			       const struct nls_table *nls_codepage, int remap);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 672ef35..f87e85f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -4089,13 +4089,13 @@ QFileInfoRetry:
 	return rc;
 }
 
-int
-CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
-		 const char *search_name, FILE_ALL_INFO *data,
-		 int legacy /* old style infolevel */,
-		 const struct nls_table *nls_codepage, int remap)
+static int
+CIFSSMBQPathInfoImpl(const unsigned int xid, struct cifs_tcon *tcon,
+		     const char *search_name,
+		     void *data, int size,
+		     __u16 level, __u16 bcc,
+		     const struct nls_table *nls_codepage, int remap)
 {
-	/* level 263 SMB_QUERY_FILE_ALL_INFO */
 	TRANSACTION2_QPI_REQ *pSMB = NULL;
 	TRANSACTION2_QPI_RSP *pSMBr = NULL;
 	int rc = 0;
@@ -4103,7 +4103,7 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
 	int name_len;
 	__u16 params, byte_count;
 
-	/* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
+	cifs_dbg(FYI, "In QPathInfo level %u path %s", level, search_name);
 QPathInfoRetry:
 	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
 		      (void **) &pSMBr);
@@ -4142,10 +4142,7 @@ QPathInfoRetry:
 	byte_count = params + 1 /* pad */ ;
 	pSMB->TotalParameterCount = cpu_to_le16(params);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
-	if (legacy)
-		pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
-	else
-		pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+	pSMB->InformationLevel = cpu_to_le16(level);
 	pSMB->Reserved4 = 0;
 	inc_rfc1001_len(pSMB, byte_count);
 	pSMB->ByteCount = cpu_to_le16(byte_count);
@@ -4159,25 +4156,10 @@ QPathInfoRetry:
 
 		if (rc) /* BB add auto retry on EOPNOTSUPP? */
 			rc = -EIO;
-		else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
+		else if (get_bcc(&pSMBr->hdr) < bcc)
 			rc = -EIO;	/* bad smb */
-		else if (legacy && get_bcc(&pSMBr->hdr) < 24)
-			rc = -EIO;  /* 24 or 26 expected but we do not read
-					last field */
 		else if (data) {
-			int size;
 			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-
-			/*
-			 * On legacy responses we do not read the last field,
-			 * EAsize, fortunately since it varies by subdialect and
-			 * also note it differs on Set vs Get, ie two bytes or 4
-			 * bytes depending but we don't care here.
-			 */
-			if (legacy)
-				size = sizeof(FILE_INFO_STANDARD);
-			else
-				size = sizeof(FILE_ALL_INFO);
 			memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
 			       data_offset, size);
 		} else
@@ -4191,6 +4173,57 @@ QPathInfoRetry:
 }
 
 int
+CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
+		 const char *search_name, FILE_ALL_INFO *data,
+		 int legacy /* old style infolevel */,
+		 const struct nls_table *nls_codepage, int remap)
+{
+	if (legacy) {
+		/* 
+		 * 24 or 26 expected but on legacy responses we do not read the
+		 * last field, EAsize, fortunately since it varies by subdialect
+		 * and also note it differs on Set vs. Get, ie two bytes or 4
+		 * bytes depending but we don't care here
+		 */
+		return CIFSSMBQPathInfoImpl(xid, tcon, search_name,
+					    data, sizeof(FILE_INFO_STANDARD),
+					    SMB_INFO_STANDARD,
+					    sizeof(FILE_INFO_STANDARD),
+					    nls_codepage, remap);
+	} else {
+		return CIFSSMBQPathInfoImpl(xid, tcon, search_name,
+					    data, sizeof(FILE_ALL_INFO),
+					    SMB_QUERY_FILE_ALL_INFO,
+					    sizeof(FILE_ALL_INFO),
+					    nls_codepage, remap);
+	}
+}
+
+int
+CIFSSMBQPathInfoBasic(const unsigned int xid, struct cifs_tcon *tcon,
+		      const char *search_name, FILE_BASIC_INFO *data,
+		      const struct nls_table *nls_codepage, int remap)
+{
+	return CIFSSMBQPathInfoImpl(xid, tcon, search_name,
+				    data, sizeof(FILE_BASIC_INFO),
+				    SMB_QUERY_FILE_BASIC_INFO,
+				    sizeof(FILE_BASIC_INFO),
+				    nls_codepage, remap);
+}
+
+int
+CIFSSMBQPathInfoStandard(const unsigned int xid, struct cifs_tcon *tcon,
+			 const char *search_name, FILE_STANDARD_INFO *data,
+			 const struct nls_table *nls_codepage, int remap)
+{
+	return CIFSSMBQPathInfoImpl(xid, tcon, search_name,
+				    data, sizeof(FILE_STANDARD_INFO),
+				    SMB_QUERY_FILE_STANDARD_INFO,
+				    sizeof(FILE_STANDARD_INFO),
+				    nls_codepage, remap);
+}
+
+int
 CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
 		 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
 {
-- 
1.9.1
