// _VerifyHashFunction bool Volume::_VerifyHashFunction(hash_function_t function) { bool result = true; // iterate over the entries in the root dir until we find an entry, that // doesn't falsify the hash function DirEntryIterator iterator(fTree, fRootVNode->GetDirID(), fRootVNode->GetObjectID(), DOT_DOT_OFFSET + 1); DirItem item; int32 index = 0; while (iterator.GetNext(&item, &index) == B_OK) { DirEntry *entry = item.EntryAt(index); uint64 offset = entry->GetOffset(); // try the hash function size_t nameLen = 0; if (const char *name = item.EntryNameAt(index, &nameLen)) { uint64 testOffset = key_offset_for_name(function, name, nameLen); if (offset_hash_value(offset) != offset_hash_value(testOffset)) { result = false; break; } } // else: bad data } return result; }
/*! \brief Returns the next entry belonging to the directory. \param foundItem Pointer to a pre-allocated Item that shall be set to the found item. \param entryIndex Pointer to a pre-allocated int32 that shall be set to the found entry index. \param _entry Pointer to a pre-allocated DirEntry pointer that shall be set to the found entry. May be \c NULL. \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're through. */ status_t DirEntryIterator::GetNext(DirItem *foundItem, int32 *entryIndex, DirEntry **_entry) { status_t error = (foundItem && entryIndex ? InitCheck() : B_BAD_VALUE); // get the next DirItem, if necessary // the loop skips empty DirItems gracefully while (error == B_OK && (fIndex < 0 || fIndex >= fDirItem.GetEntryCount())) { error = fItemIterator.GetNext(&fDirItem, TYPE_DIRENTRY); if (error == B_OK) { if (fDirItem.Check() == B_OK) fIndex = 0; else // bad data: skip the item fIndex = -1; } } // get the next entry and check whether it has the correct offset if (error == B_OK) { DirEntry *entry = fDirItem.EntryAt(fIndex); if (!fFixedHash || offset_hash_value(entry->GetOffset()) == offset_hash_value(GetOffset())) { *foundItem = fDirItem; *entryIndex = fIndex; if (_entry) *_entry = entry; fIndex++; } else error = B_ENTRY_NOT_FOUND; } return error; }
/*! \brief Returns the previous entry belonging to the directory. \param foundItem Pointer to a pre-allocated Item that shall be set to the found item. \param entryIndex Pointer to a pre-allocated int32 that shall be set to the found entry index. \param _entry Pointer to a pre-allocated DirEntry pointer that shall be set to the found entry. May be \c NULL. \return \c B_OK, if everything went fine, \c B_ENTRY_NOT_FOUND, if we're through. */ status_t DirEntryIterator::GetPrevious(DirItem *foundItem, int32 *entryIndex, DirEntry **_entry) { //printf("DirEntryIterator::GetPrevious()\n"); status_t error = (foundItem && entryIndex ? InitCheck() : B_BAD_VALUE); if (error == B_OK && fDone) error = B_ENTRY_NOT_FOUND; // get the next DirItem, if necessary // the loop skips empty DirItems gracefully while (error == B_OK && (fIndex < 0 || fIndex >= fDirItem.GetEntryCount())) { error = fItemIterator.GetPrevious(&fDirItem, TYPE_DIRENTRY); if (error == B_OK) { if (fDirItem.Check() == B_OK) fIndex = fDirItem.GetEntryCount() - 1; else // bad data: skip the item fIndex = -1; } } //printf(" found dir item: %s\n", strerror(error)); // skip entries with a greater offset while (error == B_OK && fIndex >= 0 && fDirItem.EntryAt(fIndex)->GetOffset() > GetOffset()) { //printf(" skipping entry %ld: offset %lu\n", fIndex, fDirItem.EntryAt(fIndex)->GetOffset()); fIndex--; } // get the entry and check whether it has the correct offset if (error == B_OK) { //printf(" entries with greater offsets skipped: index: %ld\n", fIndex); if (fIndex >= 0 //&& (printf(" entry index %ld: offset %lu\n", fIndex, fDirItem.EntryAt(fIndex)->GetOffset()), true) && (!fFixedHash || offset_hash_value(fDirItem.EntryAt(fIndex)->GetOffset()) == offset_hash_value(GetOffset()))) { //printf(" entry found\n"); DirEntry *entry = fDirItem.EntryAt(fIndex); *foundItem = fDirItem; *entryIndex = fIndex; fDone = (fFixedHash && offset_generation_number(entry->GetOffset()) == 0); if (_entry) *_entry = entry; fIndex--; } else error = B_ENTRY_NOT_FOUND; } //printf("DirEntryIterator::GetPrevious() done: %s\n", strerror(error)); return error; }
// _DetectHashFunction uint32 Volume::_DetectHashFunction() { // iterate over the entries in the root dir until we find an entry, that // let us draw an unambiguous conclusion DirEntryIterator iterator(fTree, fRootVNode->GetDirID(), fRootVNode->GetObjectID(), DOT_DOT_OFFSET + 1); uint32 foundCode = UNSET_HASH; DirItem item; int32 index = 0; while (foundCode == UNSET_HASH && iterator.GetNext(&item, &index) == B_OK) { DirEntry *entry = item.EntryAt(index); uint64 offset = entry->GetOffset(); uint32 hashCodes[] = { TEA_HASH, YURA_HASH, R5_HASH }; int32 hashCodeCount = sizeof(hashCodes) / sizeof(uint32); size_t nameLen = 0; const char *name = item.EntryNameAt(index, &nameLen); if (!name) // bad data! continue; // try each hash function -- if there's a single winner, we're done, // otherwise the next entry must help for (int32 i = 0; i < hashCodeCount; i++) { hash_function_t function = hash_function_for_code(hashCodes[i]); uint64 testOffset = key_offset_for_name(function, name, nameLen); if (offset_hash_value(offset) == offset_hash_value(testOffset)) { if (foundCode != UNSET_HASH) { // ambiguous foundCode = UNSET_HASH; break; } else foundCode = hashCodes[i]; } } } return foundCode; }