// _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; }
// FindDirEntry status_t Tree::FindDirEntry(uint32 dirID, uint32 objectID, const char *name, size_t nameLen, DirItem *foundItem, int32 *entryIndex) { status_t error = (name && foundItem && entryIndex ? InitCheck() : B_BAD_VALUE); if (error == B_OK) { uint64 offset = 0; if (fVolume->GetKeyOffsetForName(name, nameLen, &offset) == B_OK) { //PRINT(("Tree::FindDirEntry(): hash function: offset: %Lu (`%.*s', %lu)\n", //offset, (int)nameLen, name, nameLen)); // offset computed -- we can directly iterate only over entries // with that offset DirEntryIterator iterator(this, dirID, objectID, offset, true); DirItem dirItem; int32 index = 0; error = B_ENTRY_NOT_FOUND; while (iterator.GetPrevious(&dirItem, &index) == B_OK) { size_t itemNameLen = 0; if (const char *itemName = dirItem.EntryNameAt(index, &itemNameLen)) { if (itemNameLen == nameLen && !strncmp(name, itemName, nameLen)) { // item found *foundItem = dirItem; *entryIndex = index; error = B_OK; break; } } } } else { //PRINT(("Tree::FindDirEntry(): no hash function\n")); // no offset (no hash function) -- do it the slow way ObjectItemIterator iterator(this, dirID, objectID); DirItem dirItem; error = B_ENTRY_NOT_FOUND; while (iterator.GetNext(&dirItem, TYPE_DIRENTRY) == B_OK) { if (dirItem.Check() != B_OK) // bad data: skip item continue; int32 index = dirItem.IndexOfName(name); if (index >= 0) { // item found *foundItem = dirItem; *entryIndex = index; error = B_OK; //PRINT((" offset: %lu\n", dirItem.EntryAt(index)->GetOffset())); break; } } } } 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; }
// reiserfs_read_dir static status_t reiserfs_read_dir(fs_volume *fs, fs_vnode *_node, void *cookie, struct dirent *buffer, size_t bufferSize, uint32 *count) { // FUNCTION_START(); Volume *volume = (Volume*)fs->private_volume; VNode *node = (VNode*)_node->private_node; FUNCTION(("node: (%Ld: %lu, %lu)\n", node->GetID(), node->GetDirID(), node->GetObjectID())); DirectoryCookie *iterator = (DirectoryCookie*)cookie; status_t error = iterator->Resume(); if (error == B_OK) { // read one entry DirItem item; int32 index = 0; DirEntry *entry = NULL; bool done = false; while (error == B_OK && !done && (error = iterator->GetNext(&item, &index, &entry)) == B_OK) { uint32 dirID = entry->GetDirID(); uint32 objectID = entry->GetObjectID(); // skip hidden entries and entries the user specified to be hidden if (entry->IsHidden() || volume->IsNegativeEntry(dirID, objectID)) continue; // skip entry, if we can't get the stat data, or it is neither a // file, a dir nor a symlink and the user desired to hide those. StatData statData; StatItem statItem; if (volume->GetTree()->FindStatItem(dirID, objectID, &statItem) != B_OK || statItem.GetStatData(&statData) != B_OK || (statData.IsEsoteric() && volume->GetHideEsoteric())) { continue; } if (error == B_OK) { // get the name size_t nameLen = 0; const char *name = item.EntryNameAt(index, &nameLen); if (!name || nameLen == 0) // bad data: skip it gracefully continue; // fill in the entry name -- checks whether the // entry fits into the buffer error = set_dirent_name(buffer, bufferSize, name, nameLen); if (error == B_OK) { // fill in the other data buffer->d_dev = volume->GetID(); buffer->d_ino = VNode::GetIDFor(dirID, objectID); *count = 1; PRINT(("Successfully read entry: dir: (%Ld: %ld, %ld), name: `%s', " "id: (%Ld, %ld, %ld), reclen: %hu\n", node->GetID(), node->GetDirID(), node->GetObjectID(), buffer->d_name, buffer->d_ino, dirID, objectID, buffer->d_reclen)); if (!strcmp("..", buffer->d_name)) iterator->SetEncounteredDotDot(true); done = true; } } } if (error == B_ENTRY_NOT_FOUND) { if (iterator->EncounteredDotDot()) { error = B_OK; *count = 0; } else { // this is necessary for the root directory // it usually has no ".." entry, so we simulate one // get the name const char *name = ".."; size_t nameLen = strlen(name); // fill in the entry name -- checks whether the // entry fits into the buffer error = set_dirent_name(buffer, bufferSize, name, nameLen); if (error == B_OK) { // fill in the other data buffer->d_dev = volume->GetID(); buffer->d_ino = node->GetID(); // < That's not correct! *count = 1; PRINT(("faking `..' entry: dir: (%Ld: %ld, %ld), name: `%s', " "id: (%Ld, %ld, %ld), reclen: %hu\n", node->GetID(), node->GetDirID(), node->GetObjectID(), buffer->d_name, buffer->d_ino, node->GetDirID(), node->GetObjectID(), buffer->d_reclen)); iterator->SetEncounteredDotDot(true); } } } iterator->Suspend(); } PRINT(("returning %ld entries\n", *count)); RETURN_ERROR(error); }