// _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 Searches an entry in a directory. \note Must not be called with \a entryName "." or ".."! \param dir The directory. \param entryName Name of the entry. \param foundNode pointer to a pre-allocated VNode to be initialized to the found entry. \param failIfHidden The method shall fail, if the entry is hidden. \return \c B_OK, if everything went fine. */ status_t Volume::FindDirEntry(VNode *dir, const char *entryName, VNode *foundNode, bool failIfHidden) { status_t error = (dir && foundNode ? B_OK : B_BAD_VALUE); // find the DirEntry DirItem item; int32 entryIndex = 0; if (error == B_OK) { error = fTree->FindDirEntry(dir->GetDirID(), dir->GetObjectID(), entryName, &item, &entryIndex); } // find the child node if (error == B_OK) { DirEntry *entry = item.EntryAt(entryIndex); error = FindVNode(entry->GetDirID(), entry->GetObjectID(), foundNode); if (error == B_OK && failIfHidden && entry->IsHidden()) error = B_ENTRY_NOT_FOUND; } 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; }
/*! \brief Finds the node identified by a directory ID, object ID pair. \note The method does not initialize the parent ID for non-directory nodes. \param dirID Directory ID of the node to be found. \param objectID Object ID of the node to be found. \param node pointer to a pre-allocated VNode to be initialized to the found node. \return \c B_OK, if everything went fine. */ status_t Volume::FindVNode(uint32 dirID, uint32 objectID, VNode *node) { // NOTE: The node's parent dir ID is not initialized! status_t error = (node ? B_OK : B_BAD_VALUE); // init the node if (error == B_OK) error = node->SetTo(dirID, objectID); // find the stat item StatItem item; if (error == B_OK) { error = fTree->FindStatItem(dirID, objectID, &item); if (error != B_OK) { FATAL(("Couldn't find stat item for node (%lu, %lu)\n", dirID, objectID)); } } // get the stat data if (error == B_OK) SET_ERROR(error, item.GetStatData(node->GetStatData(), true)); // for dirs get the ".." entry, since we need the parent dir ID if (error == B_OK && node->IsDir()) { DirItem dirItem; int32 index = 0; error = fTree->FindDirEntry(dirID, objectID, "..", &dirItem, &index); if (error == B_OK) { DirEntry *entry = dirItem.EntryAt(index); node->SetParentID(entry->GetDirID(), entry->GetObjectID()); } else { FATAL(("failed to find `..' entry for dir node (%lu, %ld)\n", dirID, objectID)); } } return error; }