Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
status_t
DirEntryTree::_InitReadOnly()
{
	if (!fRootBlock.GetReadable(fDirectory->GetVolume(),
			fDirectory->BlockIndex())) {
		RETURN_ERROR(B_ERROR);
	}

	return _InitCommon();
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
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;
}