status_t SymLink::ReadSymLink(char* buffer, size_t toRead, size_t& _bytesRead) { uint64 size = Size(); if (size > kMaxSymLinkSize) RETURN_ERROR(B_BAD_DATA); if (toRead > size) toRead = size; if (toRead == 0) { _bytesRead = 0; return B_OK; } // get the block Block block; if (!block.GetReadable(GetVolume(), BlockIndex())) RETURN_ERROR(B_ERROR); const char* data = (char*)block.Data() + kSymLinkDataOffset; memcpy(buffer, data, toRead); _bytesRead = toRead; return B_OK; }
status_t Volume::ReadNode(uint64 blockIndex, Node*& _node) { if (blockIndex == 0 || blockIndex >= fTotalBlocks) return B_BAD_VALUE; // load the node's block Block block; if (!block.GetReadable(this, blockIndex)) return B_ERROR; checksumfs_node* nodeData = (checksumfs_node*)block.Data(); // create the Node object Node* node; switch (nodeData->mode & S_IFMT) { // TODO: Don't directly access mode! case S_IFDIR: node = new(std::nothrow) Directory(this, blockIndex, *nodeData); break; default: node = new(std::nothrow) Node(this, blockIndex, *nodeData); break; } if (node == NULL) return B_NO_MEMORY; // TODO: Sanity check the node! _node = node; return B_OK; }
status_t DirEntryTree::_InitReadOnly() { if (!fRootBlock.GetReadable(fDirectory->GetVolume(), fDirectory->BlockIndex())) { RETURN_ERROR(B_ERROR); } return _InitCommon(); }
status_t Volume::Mount(fs_volume* fsVolume) { fFSVolume = fsVolume; // load the superblock Block block; if (!block.GetReadable(this, kCheckSumFSSuperBlockOffset / B_PAGE_SIZE)) RETURN_ERROR(B_ERROR); SuperBlock* superBlock = (SuperBlock*)block.Data(); if (!superBlock->Check(fTotalBlocks)) RETURN_ERROR(B_BAD_DATA); // copy the volume name fName = strdup(superBlock->Name()); if (fName == NULL) RETURN_ERROR(B_NO_MEMORY); // init the block allocator status_t error = fBlockAllocator->Init(superBlock->BlockBitmap(), superBlock->FreeBlocks()); if (error != B_OK) RETURN_ERROR(error); // load the root directory Node* rootNode; error = ReadNode(superBlock->RootDirectory(), rootNode); if (error != B_OK) RETURN_ERROR(error); fRootDirectory = dynamic_cast<Directory*>(rootNode); if (fRootDirectory == NULL) { delete rootNode; RETURN_ERROR(B_BAD_DATA); } error = PublishNode(fRootDirectory, 0); if (error != B_OK) { delete fRootDirectory; fRootDirectory = NULL; return error; } return B_OK; }
status_t DirEntryTree::LookupEntry(const char* name, uint64& _blockIndex) { FUNCTION("name: \"%s\"\n", name); status_t error = _InitReadOnly(); if (error != B_OK) RETURN_ERROR(error); size_t nameLength = strlen(name); if (nameLength > kCheckSumFSNameLength) RETURN_ERROR(B_ENTRY_NOT_FOUND); uint32 depth = _Depth(); DirEntryBlock entryBlock(fRootEntryBlock, fRootEntryBlockSize); ASSERT(entryBlock.Check()); Block block; for (uint32 level = 0; level <= depth; level++) { if (entryBlock.EntryCount() == 0) RETURN_ERROR(level == 0 ? B_ENTRY_NOT_FOUND : B_BAD_DATA); bool exactMatch; int32 index = entryBlock.FindInsertionIndex(name, nameLength, exactMatch); // If we haven't found an exact match, the index points to the first // entry that is greater or after the last entry. if (!exactMatch) { if (index == 0) { // The first entry is already greater, so the branch doesn't // contain the entry we're looking for. RETURN_ERROR(B_ENTRY_NOT_FOUND); } index--; } PRINT(" level %" B_PRId32 " -> index: %" B_PRId32 " %sexact\n", level, index, exactMatch ? "" : " not "); uint64 blockIndex = entryBlock.BlockIndexAt(index); if (level == depth) { // final level -- here we should have an exact match if (!exactMatch) RETURN_ERROR(B_ENTRY_NOT_FOUND); _blockIndex = blockIndex; return B_OK; } // not the final level -- load the block and descend to the next // level if (!block.GetReadable(fDirectory->GetVolume(), blockIndex)) RETURN_ERROR(B_ERROR); entryBlock.SetTo((checksumfs_dir_entry_block*)block.Data(), B_PAGE_SIZE); ASSERT(entryBlock.Check()); } // cannot get here, but keep the compiler happy RETURN_ERROR(B_ENTRY_NOT_FOUND); }
bool DirEntryTree::_Check(int32 level, uint64 blockIndex, const char* key, size_t keyLength, DirEntryBlock& entryBlock) { // check block for validity if (!entryBlock.Check()) { ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %" B_PRIu64 " not valid!\n", level, blockIndex); return false; } // The root block is allowed to be empty. For all other blocks that is an // error. uint32 entryCount = entryBlock.EntryCount(); if (entryCount == 0) { if (level == 0) return true; ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %" B_PRIu64 " empty!\n", level, blockIndex); return false; } // Verify that the block's first entry matches the key with which the // parent block refers to it. if (level > 0) { size_t nameLength; const char* name = entryBlock.NameAt(0, nameLength); if (nameLength != keyLength || strncmp(name, key, keyLength) != 0) { ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %" B_PRIu64 " key mismatch: is \"%.*s\", should be \"%.*s\"\n", level, blockIndex, (int)keyLength, key, (int)nameLength, name); return false; } } if (level == _Depth()) return true; // not the final level -- recurse for (uint32 i = 0; i < entryCount; i++) { size_t nameLength; const char* name = entryBlock.NameAt(i, nameLength); uint64 childBlockIndex = entryBlock.BlockIndexAt(i); Block childBlock; if (!childBlock.GetReadable(fDirectory->GetVolume(), childBlockIndex)) { ERROR("DirEntryTree::Check(): level %" B_PRIu32 ": block %" B_PRIu64 " failed to get child block %" B_PRIu64 " (entry %" B_PRIu32 ")\n", level, blockIndex, childBlockIndex, i); } DirEntryBlock childEntryBlock( (checksumfs_dir_entry_block*)childBlock.Data(), B_PAGE_SIZE); if (!_Check(level + 1, childBlockIndex, name, nameLength, childEntryBlock)) { return false; } } return true; }