|
@@ -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,
|
|
|
|
- char *EAData, size_t buf_size,
|
|
|
|
- const struct nls_table *nls_codepage, int remap)
|
|
|
|
|
|
+ const unsigned char *searchName, const unsigned char *ea_name,
|
|
|
|
+ char *EAData, size_t buf_size,
|
|
|
|
+ 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 */
|
|
|
|
- name_len *= 2;
|
|
|
|
|
|
+ list_len++; /* trailing null */
|
|
|
|
+ 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);
|
|
|
|
- name_len++; /* trailing null */
|
|
|
|
- strncpy(pSMB->FileName, searchName, name_len);
|
|
|
|
|
|
+ list_len = strnlen(searchName, PATH_MAX);
|
|
|
|
+ list_len++; /* trailing null */
|
|
|
|
+ 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,237 +5346,117 @@ 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 */
|
|
|
|
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
|
+ goto QAllEAsOut;
|
|
|
|
+ }
|
|
|
|
|
|
- /* 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
|
|
|
|
- in value len */
|
|
|
|
- /* go on to next EA */
|
|
|
|
- temp_fea = (struct fea *)temp_ptr;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ /* BB also check enough total bytes returned */
|
|
|
|
+ /* BB we need to improve the validity checking
|
|
|
|
+ of these trans2 responses */
|
|
|
|
+
|
|
|
|
+ rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
+ if (rc || (pSMBr->ByteCount < 4)) {
|
|
|
|
+ rc = -EIO; /* bad smb */
|
|
|
|
+ goto QAllEAsOut;
|
|
}
|
|
}
|
|
- cifs_buf_release(pSMB);
|
|
|
|
- if (rc == -EAGAIN)
|
|
|
|
- goto QAllEAsRetry;
|
|
|
|
|
|
|
|
- return (ssize_t)rc;
|
|
|
|
-}
|
|
|
|
|
|
+ /* 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 */
|
|
|
|
|
|
-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;
|
|
|
|
|
|
+ data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
|
+ ea_response_data = (struct fealist *)
|
|
|
|
+ (((char *) &pSMBr->hdr.Protocol) + data_offset);
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
+ /* 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;
|
|
}
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
+ /* 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;
|
|
|
|
+ }
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
|
|
- /* 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;
|
|
|
|
|
|
+ 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 QEARetry;
|
|
|
|
|
|
+ goto QAllEAsRetry;
|
|
|
|
|
|
return (ssize_t)rc;
|
|
return (ssize_t)rc;
|
|
}
|
|
}
|