+
+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, 0);
+ if (rc) {
+ cFYI(1, ("Error in Notify = %d", rc));
+ }
+ if (pSMB)
+ cifs_buf_release(pSMB);
+/* if (rc == -EAGAIN)
+ goto NotifyRetry; */
+ 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, 530
+ /* 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, 530);
+ 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 */
+ __u16 data_offset = le16_to_cpu(pSMBr->DataOffset);
+ /* BB also check enough total bytes returned */
+ /* BB we need to improve the validity checking
+ of these trans2 responses */
+ if ((pSMBr->ByteCount < 4) || (data_offset > 512))
+ 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 */
+ 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, 530
+ /* 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, 530);
+ 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 */
+ __u16 data_offset = le16_to_cpu(pSMBr->DataOffset);
+ /* BB also check enough total bytes returned */
+ /* BB we need to improve the validity checking
+ of these trans2 responses */
+ if ((pSMBr->ByteCount < 4) || (data_offset > 512))
+ 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 */
+ struct fealist * ea_response_data;
+ rc = -ENOENT;
+ /* 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, 530
+ /* 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, 530);
+ 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 */
+ 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));
+ }
+
+ if (pSMB)
+ cifs_buf_release(pSMB);
+
+ if (rc == -EAGAIN)
+ goto SetEARetry;
+
+ return rc;
+}
+
+#endif