Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: [CIFS] pSesInfo->sesSem is used as mutex. Rename it to session_mutex and [CIFS] Use unsigned ea length for clarity cifs: set server_eof in cifs_fattr_to_inode [CIFS] Minor cleanup to EA patch cifs: merge CIFSSMBQueryEA with CIFSSMBQAllEAs cifs: verify lengths of QueryAllEAs reply cifs: increase maximum buffer size in CIFSSMBQAllEAs cifs: rename name_len to list_len in CIFSSMBQAllEAs cifs: clean up indentation in CIFSSMBQAllEAs cifs: add parens around smb_var in BCC macros
This commit is contained in:
commit
4846546f7e
|
@ -1,6 +1,7 @@
|
||||||
Version 1.62
|
Version 1.62
|
||||||
------------
|
------------
|
||||||
Add sockopt=TCP_NODELAY mount option.
|
Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened
|
||||||
|
to more strictly handle corrupt frames.
|
||||||
|
|
||||||
Version 1.61
|
Version 1.61
|
||||||
------------
|
------------
|
||||||
|
|
|
@ -205,7 +205,7 @@ struct cifsUidInfo {
|
||||||
struct cifsSesInfo {
|
struct cifsSesInfo {
|
||||||
struct list_head smb_ses_list;
|
struct list_head smb_ses_list;
|
||||||
struct list_head tcon_list;
|
struct list_head tcon_list;
|
||||||
struct semaphore sesSem;
|
struct mutex session_mutex;
|
||||||
#if 0
|
#if 0
|
||||||
struct cifsUidInfo *uidInfo; /* pointer to user info */
|
struct cifsUidInfo *uidInfo; /* pointer to user info */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -415,10 +415,10 @@ struct smb_hdr {
|
||||||
__u8 WordCount;
|
__u8 WordCount;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
/* given a pointer to an smb_hdr retrieve the value of byte count */
|
/* given a pointer to an smb_hdr retrieve the value of byte count */
|
||||||
#define BCC(smb_var) (*(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
|
#define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount)))
|
||||||
#define BCC_LE(smb_var) (*(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
|
#define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount)))
|
||||||
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
|
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
|
||||||
#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2)
|
#define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Computer Name Length (since Netbios name was length 16 with last byte 0x20)
|
* Computer Name Length (since Netbios name was length 16 with last byte 0x20)
|
||||||
|
|
|
@ -363,13 +363,10 @@ extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
||||||
__u32 filter, struct file *file, int multishot,
|
__u32 filter, struct file *file, int multishot,
|
||||||
const struct nls_table *nls_codepage);
|
const struct nls_table *nls_codepage);
|
||||||
extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
|
extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
|
||||||
const unsigned char *searchName, char *EAData,
|
const unsigned char *searchName,
|
||||||
|
const unsigned char *ea_name, char *EAData,
|
||||||
size_t bufsize, const struct nls_table *nls_codepage,
|
size_t bufsize, const struct nls_table *nls_codepage,
|
||||||
int remap_special_chars);
|
int remap_special_chars);
|
||||||
extern 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, int remap_special_chars);
|
|
||||||
extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
|
extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
|
||||||
const char *fileName, const char *ea_name,
|
const char *fileName, const char *ea_name,
|
||||||
const void *ea_value, const __u16 ea_value_len,
|
const void *ea_value, const __u16 ea_value_len,
|
||||||
|
|
|
@ -170,19 +170,19 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
|
||||||
* need to prevent multiple threads trying to simultaneously
|
* need to prevent multiple threads trying to simultaneously
|
||||||
* reconnect the same SMB session
|
* reconnect the same SMB session
|
||||||
*/
|
*/
|
||||||
down(&ses->sesSem);
|
mutex_lock(&ses->session_mutex);
|
||||||
if (ses->need_reconnect)
|
if (ses->need_reconnect)
|
||||||
rc = cifs_setup_session(0, ses, nls_codepage);
|
rc = cifs_setup_session(0, ses, nls_codepage);
|
||||||
|
|
||||||
/* do we need to reconnect tcon? */
|
/* do we need to reconnect tcon? */
|
||||||
if (rc || !tcon->need_reconnect) {
|
if (rc || !tcon->need_reconnect) {
|
||||||
up(&ses->sesSem);
|
mutex_unlock(&ses->session_mutex);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_open_files_invalid(tcon);
|
mark_open_files_invalid(tcon);
|
||||||
rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
|
rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
|
||||||
up(&ses->sesSem);
|
mutex_unlock(&ses->session_mutex);
|
||||||
cFYI(1, ("reconnect tcon rc = %d", rc));
|
cFYI(1, ("reconnect tcon rc = %d", rc));
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -700,13 +700,13 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
|
||||||
if (!ses || !ses->server)
|
if (!ses || !ses->server)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
down(&ses->sesSem);
|
mutex_lock(&ses->session_mutex);
|
||||||
if (ses->need_reconnect)
|
if (ses->need_reconnect)
|
||||||
goto session_already_dead; /* no need to send SMBlogoff if uid
|
goto session_already_dead; /* no need to send SMBlogoff if uid
|
||||||
already closed due to reconnect */
|
already closed due to reconnect */
|
||||||
rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
|
rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
up(&ses->sesSem);
|
mutex_unlock(&ses->session_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,7 +721,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
|
||||||
pSMB->AndXCommand = 0xFF;
|
pSMB->AndXCommand = 0xFF;
|
||||||
rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
|
rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
|
||||||
session_already_dead:
|
session_already_dead:
|
||||||
up(&ses->sesSem);
|
mutex_unlock(&ses->session_mutex);
|
||||||
|
|
||||||
/* if session dead then we do not need to do ulogoff,
|
/* if session dead then we do not need to do ulogoff,
|
||||||
since server closed smb session, no sense reporting
|
since server closed smb session, no sense reporting
|
||||||
|
@ -5269,22 +5269,34 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
||||||
cifs_buf_release(pSMB);
|
cifs_buf_release(pSMB);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_XATTR
|
#ifdef CONFIG_CIFS_XATTR
|
||||||
|
/*
|
||||||
|
* Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
|
||||||
|
* function used by listxattr and getxattr type calls. When ea_name is set,
|
||||||
|
* it looks for that attribute name and stuffs that value into the EAData
|
||||||
|
* buffer. When ea_name is NULL, it stuffs a list of attribute names into the
|
||||||
|
* buffer. In both cases, the return value is either the length of the
|
||||||
|
* resulting data or a negative error code. If EAData is a NULL pointer then
|
||||||
|
* the data isn't copied to it, but the length is returned.
|
||||||
|
*/
|
||||||
ssize_t
|
ssize_t
|
||||||
CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
|
CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
|
||||||
const unsigned char *searchName,
|
const unsigned char *searchName, const unsigned char *ea_name,
|
||||||
char *EAData, size_t buf_size,
|
char *EAData, size_t buf_size,
|
||||||
const struct nls_table *nls_codepage, int remap)
|
const struct nls_table *nls_codepage, int remap)
|
||||||
{
|
{
|
||||||
/* BB assumes one setup word */
|
/* BB assumes one setup word */
|
||||||
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
TRANSACTION2_QPI_REQ *pSMB = NULL;
|
||||||
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
TRANSACTION2_QPI_RSP *pSMBr = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int bytes_returned;
|
int bytes_returned;
|
||||||
int name_len;
|
int list_len;
|
||||||
|
struct fealist *ea_response_data;
|
||||||
struct fea *temp_fea;
|
struct fea *temp_fea;
|
||||||
char *temp_ptr;
|
char *temp_ptr;
|
||||||
__u16 params, byte_count;
|
char *end_of_smb;
|
||||||
|
__u16 params, byte_count, data_offset;
|
||||||
|
|
||||||
cFYI(1, ("In Query All EAs path %s", searchName));
|
cFYI(1, ("In Query All EAs path %s", searchName));
|
||||||
QAllEAsRetry:
|
QAllEAsRetry:
|
||||||
|
@ -5294,22 +5306,22 @@ QAllEAsRetry:
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
||||||
name_len =
|
list_len =
|
||||||
cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
|
cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
|
||||||
PATH_MAX, nls_codepage, remap);
|
PATH_MAX, nls_codepage, remap);
|
||||||
name_len++; /* trailing null */
|
list_len++; /* trailing null */
|
||||||
name_len *= 2;
|
list_len *= 2;
|
||||||
} else { /* BB improve the check for buffer overruns BB */
|
} else { /* BB improve the check for buffer overruns BB */
|
||||||
name_len = strnlen(searchName, PATH_MAX);
|
list_len = strnlen(searchName, PATH_MAX);
|
||||||
name_len++; /* trailing null */
|
list_len++; /* trailing null */
|
||||||
strncpy(pSMB->FileName, searchName, name_len);
|
strncpy(pSMB->FileName, searchName, list_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
|
params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
|
||||||
pSMB->TotalDataCount = 0;
|
pSMB->TotalDataCount = 0;
|
||||||
pSMB->MaxParameterCount = cpu_to_le16(2);
|
pSMB->MaxParameterCount = cpu_to_le16(2);
|
||||||
/* BB find exact max SMB PDU from sess structure BB */
|
/* BB find exact max SMB PDU from sess structure BB */
|
||||||
pSMB->MaxDataCount = cpu_to_le16(4000);
|
pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
|
||||||
pSMB->MaxSetupCount = 0;
|
pSMB->MaxSetupCount = 0;
|
||||||
pSMB->Reserved = 0;
|
pSMB->Reserved = 0;
|
||||||
pSMB->Flags = 0;
|
pSMB->Flags = 0;
|
||||||
|
@ -5334,85 +5346,114 @@ QAllEAsRetry:
|
||||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cFYI(1, ("Send error in QueryAllEAs = %d", rc));
|
cFYI(1, ("Send error in QueryAllEAs = %d", rc));
|
||||||
} else { /* decode response */
|
goto QAllEAsOut;
|
||||||
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 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 the SMB BB*/
|
|
||||||
|
|
||||||
/* no trailing null to account for
|
/* BB also check enough total bytes returned */
|
||||||
in value len */
|
/* BB we need to improve the validity checking
|
||||||
/* go on to next EA */
|
of these trans2 responses */
|
||||||
temp_fea = (struct fea *)temp_ptr;
|
|
||||||
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||||
|
if (rc || (pSMBr->ByteCount < 4)) {
|
||||||
|
rc = -EIO; /* bad smb */
|
||||||
|
goto QAllEAsOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that length of list is not more than bcc */
|
||||||
|
/* check that each entry does not go beyond length
|
||||||
|
of list */
|
||||||
|
/* check that each element of each entry does not
|
||||||
|
go beyond end of list */
|
||||||
|
/* validate_trans2_offsets() */
|
||||||
|
/* BB check if start of smb + data_offset > &bcc+ bcc */
|
||||||
|
|
||||||
|
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||||
|
ea_response_data = (struct fealist *)
|
||||||
|
(((char *) &pSMBr->hdr.Protocol) + data_offset);
|
||||||
|
|
||||||
|
list_len = le32_to_cpu(ea_response_data->list_len);
|
||||||
|
cFYI(1, ("ea length %d", list_len));
|
||||||
|
if (list_len <= 8) {
|
||||||
|
cFYI(1, ("empty EA list returned from server"));
|
||||||
|
goto QAllEAsOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure list_len doesn't go past end of SMB */
|
||||||
|
end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
|
||||||
|
if ((char *)ea_response_data + list_len > end_of_smb) {
|
||||||
|
cFYI(1, ("EA list appears to go beyond SMB"));
|
||||||
|
rc = -EIO;
|
||||||
|
goto QAllEAsOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* account for ea list len */
|
||||||
|
list_len -= 4;
|
||||||
|
temp_fea = ea_response_data->list;
|
||||||
|
temp_ptr = (char *)temp_fea;
|
||||||
|
while (list_len > 0) {
|
||||||
|
unsigned int name_len;
|
||||||
|
__u16 value_len;
|
||||||
|
|
||||||
|
list_len -= 4;
|
||||||
|
temp_ptr += 4;
|
||||||
|
/* make sure we can read name_len and value_len */
|
||||||
|
if (list_len < 0) {
|
||||||
|
cFYI(1, ("EA entry goes beyond length of list"));
|
||||||
|
rc = -EIO;
|
||||||
|
goto QAllEAsOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
name_len = temp_fea->name_len;
|
||||||
|
value_len = le16_to_cpu(temp_fea->value_len);
|
||||||
|
list_len -= name_len + 1 + value_len;
|
||||||
|
if (list_len < 0) {
|
||||||
|
cFYI(1, ("EA entry goes beyond length of list"));
|
||||||
|
rc = -EIO;
|
||||||
|
goto QAllEAsOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ea_name) {
|
||||||
|
if (strncmp(ea_name, temp_ptr, name_len) == 0) {
|
||||||
|
temp_ptr += name_len + 1;
|
||||||
|
rc = value_len;
|
||||||
|
if (buf_size == 0)
|
||||||
|
goto QAllEAsOut;
|
||||||
|
if ((size_t)value_len > buf_size) {
|
||||||
|
rc = -ERANGE;
|
||||||
|
goto QAllEAsOut;
|
||||||
}
|
}
|
||||||
|
memcpy(EAData, temp_ptr, value_len);
|
||||||
|
goto QAllEAsOut;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* account for prefix user. and trailing null */
|
||||||
|
rc += (5 + 1 + name_len);
|
||||||
|
if (rc < (int) buf_size) {
|
||||||
|
memcpy(EAData, "user.", 5);
|
||||||
|
EAData += 5;
|
||||||
|
memcpy(EAData, temp_ptr, name_len);
|
||||||
|
EAData += name_len;
|
||||||
|
/* null terminate name */
|
||||||
|
*EAData = 0;
|
||||||
|
++EAData;
|
||||||
|
} else if (buf_size == 0) {
|
||||||
|
/* skip copy - calc size only */
|
||||||
|
} else {
|
||||||
|
/* stop before overrun buffer */
|
||||||
|
rc = -ERANGE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
temp_ptr += name_len + 1 + value_len;
|
||||||
|
temp_fea = (struct fea *)temp_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* didn't find the named attribute */
|
||||||
|
if (ea_name)
|
||||||
|
rc = -ENODATA;
|
||||||
|
|
||||||
|
QAllEAsOut:
|
||||||
cifs_buf_release(pSMB);
|
cifs_buf_release(pSMB);
|
||||||
if (rc == -EAGAIN)
|
if (rc == -EAGAIN)
|
||||||
goto QAllEAsRetry;
|
goto QAllEAsRetry;
|
||||||
|
@ -5420,155 +5461,6 @@ QAllEAsRetry:
|
||||||
return (ssize_t)rc;
|
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, int remap)
|
|
||||||
{
|
|
||||||
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 =
|
|
||||||
cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
|
|
||||||
PATH_MAX, nls_codepage, remap);
|
|
||||||
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_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 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cifs_buf_release(pSMB);
|
|
||||||
if (rc == -EAGAIN)
|
|
||||||
goto QEARetry;
|
|
||||||
|
|
||||||
return (ssize_t)rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
|
CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
|
||||||
const char *ea_name, const void *ea_value,
|
const char *ea_name, const void *ea_value,
|
||||||
|
|
|
@ -2388,13 +2388,13 @@ try_mount_again:
|
||||||
*/
|
*/
|
||||||
cifs_put_tcp_session(srvTcp);
|
cifs_put_tcp_session(srvTcp);
|
||||||
|
|
||||||
down(&pSesInfo->sesSem);
|
mutex_lock(&pSesInfo->session_mutex);
|
||||||
if (pSesInfo->need_reconnect) {
|
if (pSesInfo->need_reconnect) {
|
||||||
cFYI(1, ("Session needs reconnect"));
|
cFYI(1, ("Session needs reconnect"));
|
||||||
rc = cifs_setup_session(xid, pSesInfo,
|
rc = cifs_setup_session(xid, pSesInfo,
|
||||||
cifs_sb->local_nls);
|
cifs_sb->local_nls);
|
||||||
}
|
}
|
||||||
up(&pSesInfo->sesSem);
|
mutex_unlock(&pSesInfo->session_mutex);
|
||||||
} else if (!rc) {
|
} else if (!rc) {
|
||||||
cFYI(1, ("Existing smb sess not found"));
|
cFYI(1, ("Existing smb sess not found"));
|
||||||
pSesInfo = sesInfoAlloc();
|
pSesInfo = sesInfoAlloc();
|
||||||
|
@ -2437,12 +2437,12 @@ try_mount_again:
|
||||||
}
|
}
|
||||||
pSesInfo->linux_uid = volume_info->linux_uid;
|
pSesInfo->linux_uid = volume_info->linux_uid;
|
||||||
pSesInfo->overrideSecFlg = volume_info->secFlg;
|
pSesInfo->overrideSecFlg = volume_info->secFlg;
|
||||||
down(&pSesInfo->sesSem);
|
mutex_lock(&pSesInfo->session_mutex);
|
||||||
|
|
||||||
/* BB FIXME need to pass vol->secFlgs BB */
|
/* BB FIXME need to pass vol->secFlgs BB */
|
||||||
rc = cifs_setup_session(xid, pSesInfo,
|
rc = cifs_setup_session(xid, pSesInfo,
|
||||||
cifs_sb->local_nls);
|
cifs_sb->local_nls);
|
||||||
up(&pSesInfo->sesSem);
|
mutex_unlock(&pSesInfo->session_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* search for existing tcon to this server share */
|
/* search for existing tcon to this server share */
|
||||||
|
|
|
@ -111,6 +111,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||||
|
|
||||||
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
|
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
|
||||||
|
|
||||||
|
cifs_i->server_eof = fattr->cf_eof;
|
||||||
/*
|
/*
|
||||||
* Can't safely change the file size here if the client is writing to
|
* Can't safely change the file size here if the client is writing to
|
||||||
* it due to potential races.
|
* it due to potential races.
|
||||||
|
@ -366,7 +367,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
|
||||||
char ea_value[4];
|
char ea_value[4];
|
||||||
__u32 mode;
|
__u32 mode;
|
||||||
|
|
||||||
rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
|
rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS",
|
||||||
ea_value, 4 /* size of buf */, cifs_sb->local_nls,
|
ea_value, 4 /* size of buf */, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags &
|
cifs_sb->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
|
|
@ -79,7 +79,7 @@ sesInfoAlloc(void)
|
||||||
++ret_buf->ses_count;
|
++ret_buf->ses_count;
|
||||||
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
|
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
|
||||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||||
init_MUTEX(&ret_buf->sesSem);
|
mutex_init(&ret_buf->session_mutex);
|
||||||
}
|
}
|
||||||
return ret_buf;
|
return ret_buf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,7 +244,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
||||||
/* revalidate/getattr then populate from inode */
|
/* revalidate/getattr then populate from inode */
|
||||||
} /* BB add else when above is implemented */
|
} /* BB add else when above is implemented */
|
||||||
ea_name += 5; /* skip past user. prefix */
|
ea_name += 5; /* skip past user. prefix */
|
||||||
rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
|
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
|
||||||
buf_size, cifs_sb->local_nls,
|
buf_size, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
|
} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
|
||||||
|
@ -252,7 +252,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
||||||
goto get_ea_exit;
|
goto get_ea_exit;
|
||||||
|
|
||||||
ea_name += 4; /* skip past os2. prefix */
|
ea_name += 4; /* skip past os2. prefix */
|
||||||
rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
|
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
|
||||||
buf_size, cifs_sb->local_nls,
|
buf_size, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
|
} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
|
||||||
|
@ -364,8 +364,8 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
|
||||||
/* if proc/fs/cifs/streamstoxattr is set then
|
/* if proc/fs/cifs/streamstoxattr is set then
|
||||||
search server for EAs or streams to
|
search server for EAs or streams to
|
||||||
returns as xattrs */
|
returns as xattrs */
|
||||||
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, data, buf_size,
|
rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
|
||||||
cifs_sb->local_nls,
|
buf_size, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags &
|
cifs_sb->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue