Equation::Match() unlocked the small data section too soon (the contents

could be changed before or during the comparison).
Some style changes.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1861 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2002-11-06 22:17:21 +00:00
parent a445cd428f
commit a3d39a9e8a
+60 -51
View File
@@ -314,7 +314,7 @@ isValidPattern(char *pattern)
*/ */
status_t status_t
matchString(char *pattern,char *string) matchString(char *pattern, char *string)
{ {
while (*pattern) { while (*pattern) {
// end of string == valid end of pattern? // end of string == valid end of pattern?
@@ -468,7 +468,7 @@ Equation::Equation(char **expr)
if (*start == '"' || *start == '\'') { if (*start == '"' || *start == '\'') {
// string is quoted (start has to be on the beginning of a string) // string is quoted (start has to be on the beginning of a string)
if (ParseQuotedString(&start,&end) < B_OK) if (ParseQuotedString(&start, &end) < B_OK)
return; return;
// set string to a valid start of the equation symbol // set string to a valid start of the equation symbol
@@ -488,7 +488,7 @@ Equation::Equation(char **expr)
// get the attribute string (and trim whitespace), in case // get the attribute string (and trim whitespace), in case
// the string was not quoted // the string was not quoted
end = string - 1; end = string - 1;
skipWhitespaceReverse(&end,start); skipWhitespaceReverse(&end, start);
} }
// attribute string is empty (which is not allowed) // attribute string is empty (which is not allowed)
@@ -529,14 +529,14 @@ Equation::Equation(char **expr)
// allocate & copy the attribute string // allocate & copy the attribute string
fAttribute = CopyString(start,end); fAttribute = CopyString(start, end);
if (fAttribute == NULL) if (fAttribute == NULL)
return; return;
start = string; start = string;
if (*start == '"' || *start == '\'') { if (*start == '"' || *start == '\'') {
// string is quoted (start has to be on the beginning of a string) // string is quoted (start has to be on the beginning of a string)
if (ParseQuotedString(&start,&end) < B_OK) if (ParseQuotedString(&start, &end) < B_OK)
return; return;
string = end + 2; string = end + 2;
@@ -546,14 +546,14 @@ Equation::Equation(char **expr)
string++; string++;
end = string - 1; end = string - 1;
skipWhitespaceReverse(&end,start); skipWhitespaceReverse(&end, start);
} }
// at this point, "start" will point to the first character of the value, // at this point, "start" will point to the first character of the value,
// "end" will point to its last character, and "start" to the first non- // "end" will point to its last character, and "start" to the first non-
// whitespace character after the value string // whitespace character after the value string
fString = CopyString(start,end); fString = CopyString(start, end);
if (fString == NULL) if (fString == NULL)
return; return;
@@ -574,7 +574,7 @@ Equation::Equation(char **expr)
// later. The only index which needs this is the last_modified // later. The only index which needs this is the last_modified
// index, but we may want to open that feature for other indices, // index, but we may want to open that feature for other indices,
// too one day. // too one day.
fIsSpecialTime = !strcmp(fAttribute,"last_modified"); fIsSpecialTime = !strcmp(fAttribute, "last_modified");
*expr = string; *expr = string;
} }
@@ -623,7 +623,7 @@ Equation::ParseQuotedString(char **_start, char **_end)
char * char *
Equation::CopyString(char *start,char *end) Equation::CopyString(char *start, char *end)
{ {
// end points to the last character of the string - and the length // end points to the last character of the string - and the length
// also has to include the null-termination // also has to include the null-termination
@@ -660,36 +660,36 @@ Equation::ConvertValue(type_code type)
type = B_STRING_TYPE; type = B_STRING_TYPE;
// supposed to fall through // supposed to fall through
case B_STRING_TYPE: case B_STRING_TYPE:
strncpy(fValue.String,string,INODE_FILE_NAME_LENGTH); strncpy(fValue.String, string, INODE_FILE_NAME_LENGTH);
fValue.String[INODE_FILE_NAME_LENGTH - 1] = '\0'; fValue.String[INODE_FILE_NAME_LENGTH - 1] = '\0';
fSize = strlen(fValue.String); fSize = strlen(fValue.String);
break; break;
case B_INT32_TYPE: case B_INT32_TYPE:
fValue.Int32 = strtol(string,&string,0); fValue.Int32 = strtol(string, &string, 0);
fSize = sizeof(int32); fSize = sizeof(int32);
break; break;
case B_UINT32_TYPE: case B_UINT32_TYPE:
fValue.Int32 = strtoul(string,&string,0); fValue.Int32 = strtoul(string, &string, 0);
fSize = sizeof(uint32); fSize = sizeof(uint32);
break; break;
case B_INT64_TYPE: case B_INT64_TYPE:
fValue.Int64 = strtoll(string,&string,0); fValue.Int64 = strtoll(string, &string, 0);
fSize = sizeof(int64); fSize = sizeof(int64);
break; break;
case B_UINT64_TYPE: case B_UINT64_TYPE:
fValue.Uint64 = strtoull(string,&string,0); fValue.Uint64 = strtoull(string, &string, 0);
fSize = sizeof(uint64); fSize = sizeof(uint64);
break; break;
case B_FLOAT_TYPE: case B_FLOAT_TYPE:
fValue.Float = strtod(string,&string); fValue.Float = strtod(string, &string);
fSize = sizeof(float); fSize = sizeof(float);
break; break;
case B_DOUBLE_TYPE: case B_DOUBLE_TYPE:
fValue.Double = strtod(string,&string); fValue.Double = strtod(string, &string);
fSize = sizeof(double); fSize = sizeof(double);
break; break;
default: default:
FATAL(("query value conversion to 0x%lx requested!\n",type)); FATAL(("query value conversion to 0x%lx requested!\n", type));
// should we fail here or just do a safety int32 conversion? // should we fail here or just do a safety int32 conversion?
return B_ERROR; return B_ERROR;
} }
@@ -707,7 +707,7 @@ Equation::ConvertValue(type_code type)
*/ */
bool bool
Equation::CompareTo(const uint8 *value,uint16 size) Equation::CompareTo(const uint8 *value, uint16 size)
{ {
int32 compare; int32 compare;
@@ -772,7 +772,7 @@ Equation::MatchEmptyString()
status_t status = ConvertValue(B_STRING_TYPE); status_t status = ConvertValue(B_STRING_TYPE);
if (status == B_OK) if (status == B_OK)
status = CompareTo((const uint8 *)"",fSize) ? MATCH_OK : NO_MATCH; status = CompareTo((const uint8 *)"", fSize) ? MATCH_OK : NO_MATCH;
return status; return status;
} }
@@ -783,14 +783,15 @@ Equation::MatchEmptyString()
*/ */
status_t status_t
Equation::Match(Inode *inode,const char *attributeName,int32 type,const uint8 *key,size_t size) Equation::Match(Inode *inode, const char *attributeName, int32 type, const uint8 *key, size_t size)
{ {
// get a pointer to the attribute in question // get a pointer to the attribute in question
union value value; union value value;
uint8 *buffer; uint8 *buffer;
bool locked = false;
// first, check if we are matching for a live query and use that value // first, check if we are matching for a live query and use that value
if (attributeName != NULL && !strcmp(fAttribute,attributeName)) { if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
if (key == NULL) { if (key == NULL) {
if (type == B_STRING_TYPE) if (type == B_STRING_TYPE)
return MatchEmptyString(); return MatchEmptyString();
@@ -798,7 +799,7 @@ Equation::Match(Inode *inode,const char *attributeName,int32 type,const uint8 *k
return NO_MATCH; return NO_MATCH;
} }
buffer = const_cast<uint8 *>(key); buffer = const_cast<uint8 *>(key);
} else if (!strcmp(fAttribute,"name")) { } else if (!strcmp(fAttribute, "name")) {
// if not, check for "fake" attributes, "name", "size", "last_modified", // if not, check for "fake" attributes, "name", "size", "last_modified",
buffer = (uint8 *)inode->Name(); buffer = (uint8 *)inode->Name();
if (buffer == NULL) if (buffer == NULL)
@@ -823,12 +824,12 @@ Equation::Match(Inode *inode,const char *attributeName,int32 type,const uint8 *k
buffer = smallData->Data(); buffer = smallData->Data();
type = smallData->type; type = smallData->type;
size = smallData->data_size; size = smallData->data_size;
inode->SmallDataLock().Unlock(); locked = true;
} else { } else {
// needed to unlock the small_data section as fast as possible // needed to unlock the small_data section as fast as possible
inode->SmallDataLock().Unlock(); inode->SmallDataLock().Unlock();
if (inode->GetAttribute(fAttribute,&attribute) == B_OK) { if (inode->GetAttribute(fAttribute, &attribute) == B_OK) {
buffer = (uint8 *)&value; buffer = (uint8 *)&value;
type = attribute->Node()->type; type = attribute->Node()->type;
size = attribute->Size(); size = attribute->Size();
@@ -836,7 +837,7 @@ Equation::Match(Inode *inode,const char *attributeName,int32 type,const uint8 *k
if (size > INODE_FILE_NAME_LENGTH) if (size > INODE_FILE_NAME_LENGTH)
size = INODE_FILE_NAME_LENGTH; size = INODE_FILE_NAME_LENGTH;
if (attribute->ReadAt(0,buffer,&size) < B_OK) { if (attribute->ReadAt(0, buffer, &size) < B_OK) {
inode->ReleaseAttribute(attribute); inode->ReleaseAttribute(attribute);
return B_IO_ERROR; return B_IO_ERROR;
} }
@@ -848,7 +849,10 @@ Equation::Match(Inode *inode,const char *attributeName,int32 type,const uint8 *k
// prepare own value for use, if it is possible to convert it // prepare own value for use, if it is possible to convert it
status_t status = ConvertValue(type); status_t status = ConvertValue(type);
if (status == B_OK) if (status == B_OK)
status = CompareTo(buffer,size) ? MATCH_OK : NO_MATCH; status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
if (locked)
inode->SmallDataLock().Unlock();
RETURN_ERROR(status); RETURN_ERROR(status);
} }
@@ -950,14 +954,15 @@ Equation::PrepareQuery(Volume */*volume*/, Index &index, TreeIterator **iterator
if (fIsSpecialTime) { if (fIsSpecialTime) {
// we have to find the first matching shifted value // we have to find the first matching shifted value
off_t value = fValue.Int64 << INODE_TIME_SHIFT; off_t value = fValue.Int64 << INODE_TIME_SHIFT;
status = (*iterator)->Find((uint8 *)&value,keySize); status = (*iterator)->Find((uint8 *)&value, keySize);
if (status == B_ENTRY_NOT_FOUND) if (status == B_ENTRY_NOT_FOUND)
return B_OK; return B_OK;
} else { } else {
status = (*iterator)->Find(Value(),keySize); status = (*iterator)->Find(Value(),keySize);
if (fOp == OP_EQUAL && !fIsPattern) if (fOp == OP_EQUAL && !fIsPattern)
return status; return status;
else if (status == B_ENTRY_NOT_FOUND && (fIsPattern || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL)) else if (status == B_ENTRY_NOT_FOUND
&& (fIsPattern || fOp == OP_GREATER_THAN || fOp == OP_GREATER_THAN_OR_EQUAL))
return B_OK; return B_OK;
} }
@@ -978,13 +983,14 @@ Equation::GetNextMatching(Volume *volume, TreeIterator *iterator,
uint16 duplicate; uint16 duplicate;
off_t offset; off_t offset;
status_t status = iterator->GetNextEntry(&indexValue,&keyLength,(uint16)sizeof(indexValue),&offset,&duplicate); status_t status = iterator->GetNextEntry(&indexValue, &keyLength,
(uint16)sizeof(indexValue), &offset, &duplicate);
if (status < B_OK) if (status < B_OK)
return status; return status;
// only compare against the index entry when this is the correct // only compare against the index entry when this is the correct
// index for the equation // index for the equation
if (fHasIndex && duplicate < 2 && !CompareTo((uint8 *)&indexValue,keyLength)) { if (fHasIndex && duplicate < 2 && !CompareTo((uint8 *)&indexValue, keyLength)) {
// They aren't equal? let the operation decide what to do // They aren't equal? let the operation decide what to do
// Since we always start at the beginning of the index (or the correct // Since we always start at the beginning of the index (or the correct
// position), only some needs to be stopped if the entry doesn't fit. // position), only some needs to be stopped if the entry doesn't fit.
@@ -999,9 +1005,9 @@ Equation::GetNextMatching(Volume *volume, TreeIterator *iterator,
} }
Inode *inode; Inode *inode;
if ((status = get_vnode(volume->ID(),offset,(void **)&inode)) != B_OK) { if ((status = get_vnode(volume->ID(), offset, (void **)&inode)) != B_OK) {
REPORT_ERROR(status); REPORT_ERROR(status);
FATAL(("could not get inode %Ld in index \"%s\"!\n",offset,fAttribute)); FATAL(("could not get inode %Ld in index \"%s\"!\n", offset, fAttribute));
// try with next // try with next
continue; continue;
} }
@@ -1036,7 +1042,7 @@ Equation::GetNextMatching(Volume *volume, TreeIterator *iterator,
other = parent->Left(); other = parent->Left();
if (other == NULL) { if (other == NULL) {
FATAL(("&&-operator has only one child... (parent = %p)\n",parent)); FATAL(("&&-operator has only one child... (parent = %p)\n", parent));
break; break;
} }
status = other->Match(inode); status = other->Match(inode);
@@ -1097,22 +1103,22 @@ Operator::~Operator()
status_t status_t
Operator::Match(Inode *inode,const char *attribute,int32 type,const uint8 *key,size_t size) Operator::Match(Inode *inode, const char *attribute, int32 type, const uint8 *key, size_t size)
{ {
if (fOp == OP_AND) { if (fOp == OP_AND) {
status_t status = fLeft->Match(inode,attribute,type,key,size); status_t status = fLeft->Match(inode, attribute, type, key, size);
if (status != MATCH_OK) if (status != MATCH_OK)
return status; return status;
return fRight->Match(inode,attribute,type,key,size); return fRight->Match(inode, attribute, type, key, size);
} else { } else {
// choose the term with the better score for OP_OR // choose the term with the better score for OP_OR
if (fRight->Score() > fLeft->Score()) { if (fRight->Score() > fLeft->Score()) {
status_t status = fRight->Match(inode,attribute,type,key,size); status_t status = fRight->Match(inode, attribute, type, key, size);
if (status != NO_MATCH) if (status != NO_MATCH)
return status; return status;
} }
return fLeft->Match(inode,attribute,type,key,size); return fLeft->Match(inode, attribute, type, key, size);
} }
} }
@@ -1242,7 +1248,7 @@ Equation::PrintToStream()
case OP_LESS_THAN: symbol = "<"; break; case OP_LESS_THAN: symbol = "<"; break;
case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break; case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break;
} }
D(__out("[\"%s\" %s \"%s\"]",fAttribute,symbol,fString)); D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString));
} }
#endif /* DEBUG */ #endif /* DEBUG */
@@ -1265,7 +1271,7 @@ Expression::Expression(char *expr)
fTerm->PrintToStream(); fTerm->PrintToStream();
D(__out("\n")); D(__out("\n"));
if (*expr != '\0') if (*expr != '\0')
PRINT(("Unexpected end of string: \"%s\"!\n",expr)); PRINT(("Unexpected end of string: \"%s\"!\n", expr));
}); });
fPosition = expr; fPosition = expr;
} }
@@ -1336,7 +1342,7 @@ Expression::ParseAnd(char **expr)
Term *right = ParseAnd(expr); Term *right = ParseAnd(expr);
Term *newParent = NULL; Term *newParent = NULL;
if (right == NULL || (newParent = new Operator(left,OP_AND,right)) == NULL) { if (right == NULL || (newParent = new Operator(left, OP_AND, right)) == NULL) {
delete left; delete left;
delete right; delete right;
@@ -1360,7 +1366,7 @@ Expression::ParseOr(char **expr)
Term *right = ParseAnd(expr); Term *right = ParseAnd(expr);
Term *newParent = NULL; Term *newParent = NULL;
if (right == NULL || (newParent = new Operator(left,OP_OR,right)) == NULL) { if (right == NULL || (newParent = new Operator(left, OP_OR, right)) == NULL) {
delete left; delete left;
delete right; delete right;
@@ -1399,7 +1405,7 @@ Expression::InitCheck()
// #pragma mark - // #pragma mark -
Query::Query(Volume *volume,Expression *expression) Query::Query(Volume *volume, Expression *expression)
: :
fVolume(volume), fVolume(volume),
fExpression(expression), fExpression(expression),
@@ -1459,13 +1465,13 @@ Query::GetNextEntry(struct dirent *dirent, size_t size)
if (fIterator == NULL) { if (fIterator == NULL) {
if (!fStack.Pop(&fCurrent) if (!fStack.Pop(&fCurrent)
|| fCurrent == NULL || fCurrent == NULL
|| fCurrent->PrepareQuery(fVolume,fIndex,&fIterator) < B_OK) || fCurrent->PrepareQuery(fVolume, fIndex, &fIterator) < B_OK)
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
if (fCurrent == NULL) if (fCurrent == NULL)
RETURN_ERROR(B_ERROR); RETURN_ERROR(B_ERROR);
status_t status = fCurrent->GetNextMatching(fVolume,fIterator,dirent,size); status_t status = fCurrent->GetNextMatching(fVolume, fIterator, dirent, size);
if (status < B_OK) { if (status < B_OK) {
delete fIterator; delete fIterator;
fIterator = NULL; fIterator = NULL;
@@ -1479,7 +1485,7 @@ Query::GetNextEntry(struct dirent *dirent, size_t size)
void void
Query::SetLiveMode(port_id port,int32 token) Query::SetLiveMode(port_id port, int32 token)
{ {
fPort = port; fPort = port;
fToken = token; fToken = token;
@@ -1487,22 +1493,24 @@ Query::SetLiveMode(port_id port,int32 token)
void void
Query::LiveUpdate(Inode *inode,const char *attribute,int32 type,const uint8 *oldKey,size_t oldLength,const uint8 *newKey,size_t newLength) Query::LiveUpdate(Inode *inode, const char *attribute, int32 type, const uint8 *oldKey,
size_t oldLength, const uint8 *newKey, size_t newLength)
{ {
if (fPort < 0 || fExpression == NULL || attribute == NULL) if (fPort < 0 || fExpression == NULL || attribute == NULL)
return; return;
// ToDo: check if the attribute is part of the query at all... // ToDo: check if the attribute is part of the query at all...
status_t oldStatus = fExpression->Root()->Match(inode,attribute,type,oldKey,oldLength); status_t oldStatus = fExpression->Root()->Match(inode, attribute, type, oldKey, oldLength);
status_t newStatus = fExpression->Root()->Match(inode,attribute,type,newKey,newLength); status_t newStatus = fExpression->Root()->Match(inode, attribute, type, newKey, newLength);
int32 op; int32 op;
if (oldStatus == MATCH_OK && newStatus == MATCH_OK) { if (oldStatus == MATCH_OK && newStatus == MATCH_OK) {
// only send out a notification if the name was changed // only send out a notification if the name was changed
if (oldKey == NULL || strcmp(attribute,"name")) if (oldKey == NULL || strcmp(attribute,"name"))
return; return;
send_notification(fPort,fToken,B_QUERY_UPDATE,B_ENTRY_REMOVED,fVolume->ID(),0,fVolume->ToVnode(inode->Parent()),0,inode->ID(),(const char *)oldKey); send_notification(fPort, fToken, B_QUERY_UPDATE, B_ENTRY_REMOVED, fVolume->ID(), 0,
fVolume->ToVnode(inode->Parent()), 0, inode->ID(), (const char *)oldKey);
op = B_ENTRY_CREATED; op = B_ENTRY_CREATED;
} else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) { } else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) {
// nothing has changed // nothing has changed
@@ -1517,6 +1525,7 @@ Query::LiveUpdate(Inode *inode,const char *attribute,int32 type,const uint8 *old
if (type != B_STRING_TYPE || value == NULL) if (type != B_STRING_TYPE || value == NULL)
value = ""; value = "";
send_notification(fPort,fToken,B_QUERY_UPDATE,op,fVolume->ID(),0,fVolume->ToVnode(inode->Parent()),0,inode->ID(),value); send_notification(fPort, fToken, B_QUERY_UPDATE, op, fVolume->ID(), 0,
fVolume->ToVnode(inode->Parent()), 0, inode->ID(), value);
} }